You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ar...@apache.org on 2018/04/02 11:31:59 UTC

[18/24] olingo-odata2 git commit: [OLINGO-1253]Client Module for Olingo v2

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/deserializer/XmlPropertyDeserializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/deserializer/XmlPropertyDeserializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/deserializer/XmlPropertyDeserializer.java
new file mode 100644
index 0000000..53370bc
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/deserializer/XmlPropertyDeserializer.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * 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.odata2.client.core.ep.deserializer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.DeserializerProperties;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityComplexPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityTypeMapping;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * XML property consumer.
+ */
+public class XmlPropertyDeserializer {
+
+  protected static final String TRUE = "true";
+  protected static final String FALSE = "false";
+
+  /**
+   * Read property of every entry in a payload
+   * @param reader
+   * @param property
+   * @param readProperties
+   * @return Map<String, Object>
+   * @throws EntityProviderException
+   */
+  public Map<String, Object> readProperty(final XMLStreamReader reader, final EdmProperty property,
+      final DeserializerProperties readProperties) throws EntityProviderException {
+    return readProperty(reader, EntityInfoAggregator.create(property), readProperties);
+  }
+
+  /**
+   * Read property of every entry in a payload
+   * @param reader
+   * @param propertyInfo
+   * @param readProperties
+   * @return Map<String, Object>
+   * @throws EntityProviderException
+   */
+  public Map<String, Object> readProperty(final XMLStreamReader reader, final EntityPropertyInfo propertyInfo,
+      final DeserializerProperties readProperties) throws EntityProviderException {
+    final EntityTypeMapping typeMappings =
+        EntityTypeMapping.create(readProperties  == null ? Collections.<String, Object> emptyMap() :
+      readProperties.getTypeMappings());
+    try {
+      reader.next();
+
+      Object value = readStartedElement(reader, propertyInfo.getName(), propertyInfo, typeMappings, readProperties);
+
+      Map<String, Object> result = new HashMap<String, Object>();
+      result.put(propertyInfo.getName(), value);
+      return result;
+    } catch (XMLStreamException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+          .getSimpleName()), e);
+    } catch (EdmException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+          .getSimpleName()), e);
+    }
+  }
+
+
+  /**
+   * Deserializes a collection of entities
+   * @param reader
+   * @param info
+   * @param properties
+   * @return List<Object>
+   * @throws EntityProviderException
+   */
+  public List<Object> readCollection(XMLStreamReader reader, final EntityPropertyInfo info,
+      final DeserializerProperties properties) throws EntityProviderException {
+    final String collectionName = info.getName();
+    final EntityTypeMapping typeMappings = EntityTypeMapping.create(
+        properties == null || !properties.getTypeMappings().containsKey(collectionName) ?
+            Collections.<String, Object> emptyMap() :
+            Collections.<String, Object> singletonMap(FormatXml.D_ELEMENT,
+                properties.getTypeMappings().get(collectionName)));
+    List<Object> result = new ArrayList<Object>();
+    try {
+      reader.nextTag();
+      reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_D_2007_08, collectionName);
+      reader.nextTag();
+      while (reader.isStartElement()) {
+        result.add(readStartedElement(reader, FormatXml.D_ELEMENT, info, typeMappings, properties));
+        reader.nextTag();
+      }
+      reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_D_2007_08, collectionName);
+      reader.next();
+      reader.require(XMLStreamConstants.END_DOCUMENT, null, null);
+      return result;
+    } catch (final XMLStreamException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED
+          .addContent(e.getClass().getSimpleName()), e);
+    } catch (final EdmException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED
+          .addContent(e.getClass().getSimpleName()), e);
+    }
+  }
+
+  protected Object readStartedElement(XMLStreamReader reader, final String name, //NOSONAR
+      final EntityPropertyInfo propertyInfo, 
+      final EntityTypeMapping typeMappings, final DeserializerProperties readProperties)
+      throws EntityProviderException, EdmException { 
+    Object result = null;
+
+    try {
+      reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_D_2007_08, name);
+      final String nullAttribute = reader.getAttributeValue(Edm.NAMESPACE_M_2007_08, FormatXml.M_NULL);
+
+      if (!(nullAttribute == null || TRUE.equals(nullAttribute) || FALSE.equals(nullAttribute))) {
+        throw new EntityProviderException(EntityProviderException.COMMON);
+      }
+
+      if (TRUE.equals(nullAttribute)) {
+        if ((readProperties == null || readProperties.isValidatingFacets()) && propertyInfo.isMandatory()) {
+          throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY_VALUE.addContent(name));
+        }
+        reader.nextTag();
+      } else if (propertyInfo.isComplex()) {
+        final String typeAttribute = reader.getAttributeValue(Edm.NAMESPACE_M_2007_08, FormatXml.M_TYPE);
+        if (typeAttribute != null) {
+          final String expectedTypeAttributeValue =
+              propertyInfo.getType().getNamespace() + Edm.DELIMITER + propertyInfo.getType().getName();
+          if (!expectedTypeAttributeValue.equals(typeAttribute)) { //NOSONAR
+            throw new EntityProviderException(EntityProviderException.INVALID_COMPLEX_TYPE.addContent(
+                expectedTypeAttributeValue).addContent(typeAttribute));
+          }
+        }
+
+        reader.nextTag();
+        Map<String, Object> name2Value = new HashMap<String, Object>();
+        while (reader.hasNext() && !reader.isEndElement()) {
+          final String childName = reader.getLocalName();
+          final EntityPropertyInfo childProperty =
+              ((EntityComplexPropertyInfo) propertyInfo).getPropertyInfo(childName);
+          if (childProperty == null) { //NOSONAR
+            throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY.addContent(childName));
+          }
+          final Object value = readStartedElement(reader, childName, childProperty,
+              typeMappings.getEntityTypeMapping(name), readProperties);
+          name2Value.put(childName, value);
+          reader.nextTag();
+        }
+        result = name2Value;
+      } else {
+        result = convert(propertyInfo, reader.getElementText(), typeMappings.getMappingClass(name), readProperties);
+      }
+      reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_D_2007_08, name);
+
+      return result;
+    } catch (XMLStreamException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+          .getSimpleName()), e);
+    }
+  }
+
+  private Object convert(final EntityPropertyInfo property, final String value, final Class<?> typeMapping,
+      final DeserializerProperties readProperties) throws EdmSimpleTypeException {
+    final EdmSimpleType type = (EdmSimpleType) property.getType();
+    return type.valueOfString(value, EdmLiteralKind.DEFAULT,
+        readProperties == null || readProperties.isValidatingFacets() ? property.getFacets() : null,
+        typeMapping == null ? type.getDefaultType() : typeMapping);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomEntryEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomEntryEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomEntryEntitySerializer.java
new file mode 100644
index 0000000..5881813
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomEntryEntitySerializer.java
@@ -0,0 +1,669 @@
+/*******************************************************************************
+ * 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.odata2.client.core.ep.serializer;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.Map.Entry;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmCustomizableFeedMappings;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmMapping;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.edm.EdmTargetPath;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.client.api.ep.EntityCollection;
+import org.apache.olingo.odata2.client.api.ep.EntityCollectionSerializerProperties;
+import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
+import org.apache.olingo.odata2.core.commons.ContentType;
+import org.apache.olingo.odata2.core.commons.Encoder;
+import org.apache.olingo.odata2.core.edm.EdmDateTimeOffset;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Serializes an ATOM entry.
+ * 
+ */
+public class AtomEntryEntitySerializer {
+  private final EntitySerializerProperties properties;
+  private static final String VALUE = "/$value";
+
+  /**
+   * 
+   * @param properties
+   */
+  public AtomEntryEntitySerializer(final EntitySerializerProperties properties) {
+    this.properties = properties == null ? EntitySerializerProperties.serviceRoot(null).build() : properties;
+  }
+
+  /**
+   * This serializes the xml payload entry
+   * @param writer
+   * @param eia
+   * @param data
+   * @param isRootElement
+   * @param isFeedPart
+   * @throws EntityProviderException
+   */
+  public void append(final XMLStreamWriter writer, final EntityInfoAggregator eia, final Entity data,
+      final boolean isRootElement, final boolean isFeedPart) throws EntityProviderException {
+
+    try {
+      if (properties.getServiceRoot() == null) {
+        throw new EntityProviderProducerException(EntityProviderException.MANDATORY_WRITE_PROPERTY);
+      }
+      writer.writeStartElement(FormatXml.ATOM_ENTRY);
+
+      if (isRootElement) {
+        writer.writeDefaultNamespace(Edm.NAMESPACE_ATOM_2005);
+        writer.writeNamespace(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
+        writer.writeNamespace(Edm.PREFIX_D, Edm.NAMESPACE_D_2007_08);
+      }
+      if (!isFeedPart) {
+        writer.writeAttribute(Edm.PREFIX_XML, Edm.NAMESPACE_XML_1998, FormatXml.XML_BASE, properties.getServiceRoot()
+            .toASCIIString());
+      }
+
+      String selfLink = null;
+      if (properties.isIncludeMetadata()) {
+        // write all atom infos (mandatory and optional)
+        selfLink = createSelfLink(eia, data.getProperties(), null, properties.isKeyAutoGenerated(), false);
+        appendAtomMandatoryParts(writer, eia, data.getProperties());
+        appendAtomOptionalParts(writer, eia, data.getProperties());
+        appendAtomEditLink(writer, eia, selfLink);
+        if (eia.getEntityType().hasStream()) {
+          appendAtomContentLink(writer, eia, data.getProperties(), selfLink);
+        }
+      }
+
+      appendNavigationLinks(writer, eia, data);
+      appendCustomProperties(writer, eia, data.getProperties());
+
+      if (eia.getEntityType().hasStream()) {
+        if (properties.isIncludeMetadata()) {
+          appendAtomContentPart(writer, eia, data.getProperties(), selfLink);
+        }
+        appendProperties(writer, eia, data.getProperties());
+      } else {
+        writer.writeStartElement(FormatXml.ATOM_CONTENT);
+        writer.writeAttribute(FormatXml.ATOM_TYPE, ContentType.APPLICATION_XML.toString());
+        appendProperties(writer, eia, data.getProperties());
+        writer.writeEndElement();
+      }
+      writer.writeEndElement();
+      writer.flush();
+
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    } catch (EdmException e) {
+      throw new EntityProviderProducerException(e.getMessageReference(), e);
+    } catch (URISyntaxException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  private void appendNavigationLinks(final XMLStreamWriter writer, //NOSONAR
+      final EntityInfoAggregator eia,
+      final Entity data) 
+      throws EntityProviderException, EdmException, URISyntaxException, XMLStreamException { 
+
+    for (Entry<String, Object> entry : data.getNavigations().entrySet()) {
+      final EntityInfoAggregator targetEntityInfo = EntityInfoAggregator.create(
+          eia.getEntitySet().getRelatedEntitySet(
+              (EdmNavigationProperty) eia.getEntityType().getProperty(entry.getKey())));
+      final boolean isFeed =
+          (eia.getNavigationPropertyInfo(entry.getKey()).getMultiplicity() == EdmMultiplicity.MANY);
+      if (entry.getValue() == null) {
+        throw new EntityProviderProducerException(EntityProviderProducerException.NULL_VALUE);
+      } else if (entry.getValue() instanceof Map) {
+        Map<String, Object> navigationKeyMap = (Map<String, Object>) entry.getValue();
+        if (navigationKeyMap != null && !navigationKeyMap.isEmpty()) {
+          appendAtomNavigationLink(writer, createSelfLink(targetEntityInfo, navigationKeyMap, null, 
+              properties.isKeyAutoGenerated(), false), entry.getKey(), isFeed);
+          writer.writeEndElement();
+        }
+      } else if (entry.getValue() instanceof Entity) {
+        Entity navigationEntity = (Entity) entry.getValue();
+        Map<String, Object> navigationKeyMap = navigationEntity.getProperties();
+        if (navigationKeyMap != null && !navigationKeyMap.isEmpty()) {
+          String navigationPropertyName = entry.getKey();
+          String selfLink = createSelfLink(eia, data.getProperties(), navigationPropertyName,
+              properties.isKeyAutoGenerated(), false);
+          appendNavigationLink(writer, selfLink, navigationPropertyName);
+
+          writer.writeAttribute(FormatXml.ATOM_TYPE, ContentType.APPLICATION_ATOM_XML_ENTRY.toString());
+          appendInlineEntry(writer, navigationPropertyName, eia, data);
+          writer.writeEndElement();
+
+        }
+      } else if (entry.getValue() instanceof EntityCollection) {
+        String navigationPropertyName = entry.getKey();
+        String selfLink = createSelfLink(eia, data.getProperties(), navigationPropertyName, 
+            properties.isKeyAutoGenerated(), false);
+        if (!((EntityCollection) entry.getValue()).getEntities().isEmpty()) {
+          appendNavigationLink(writer, selfLink, navigationPropertyName);
+
+          writer.writeAttribute(FormatXml.ATOM_TYPE, ContentType.APPLICATION_ATOM_XML_FEED.toString());
+          appendInlineFeed(writer, navigationPropertyName, eia, data);
+          writer.writeEndElement();
+        }
+
+      } else{
+        throw new EntityProviderProducerException(EntityProviderProducerException.INCORRECT_NAVIGATION_TYPE);
+        
+      }
+    }
+  }
+
+  private void appendNavigationLink(XMLStreamWriter writer, String selfLink, String navigationPropertyName)
+      throws XMLStreamException {
+
+    writer.writeStartElement(FormatXml.ATOM_LINK);
+    writer.writeAttribute(FormatXml.ATOM_HREF, selfLink);
+    writer.writeAttribute(FormatXml.ATOM_REL, Edm.NAMESPACE_REL_2007_08 + navigationPropertyName);
+    writer.writeAttribute(FormatXml.ATOM_TITLE, navigationPropertyName);
+  }
+
+  private void appendCustomProperties(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+      final Map<String, Object> data) throws EntityProviderException {
+    List<String> noneSyndicationTargetPaths = eia.getNoneSyndicationTargetPathNames();
+    for (String tpName : noneSyndicationTargetPaths) {
+      EntityPropertyInfo info = eia.getTargetPathInfo(tpName);
+      final String name = info.getName();
+      XmlPropertyEntitySerializer aps = new XmlPropertyEntitySerializer(properties);
+      aps.appendCustomProperty(writer, name, info, data.get(name));
+    }
+  }
+
+  private void appendAtomNavigationLink(final XMLStreamWriter writer, final String target,
+      final String navigationPropertyName, final boolean isFeed) 
+          throws EntityProviderException, EdmException, URISyntaxException { //NOSONAR
+    try {
+      writer.writeStartElement(FormatXml.ATOM_LINK);
+      writer.writeAttribute(FormatXml.ATOM_HREF, target);
+      writer.writeAttribute(FormatXml.ATOM_REL, Edm.NAMESPACE_REL_2007_08 + navigationPropertyName);
+      writer.writeAttribute(FormatXml.ATOM_TITLE, navigationPropertyName);
+      if (isFeed) {
+        writer.writeAttribute(FormatXml.ATOM_TYPE, ContentType.APPLICATION_ATOM_XML_FEED.toString());
+      } else {
+        writer.writeAttribute(FormatXml.ATOM_TYPE, ContentType.APPLICATION_ATOM_XML_ENTRY.toString());
+      }
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    }
+  }
+
+  private void appendInlineFeed(final XMLStreamWriter writer, final String navigationPropertyName,
+      final EntityInfoAggregator eia, final Entity data)
+      throws EntityProviderException, XMLStreamException, EdmException {
+
+    if (eia.getNavigationPropertyNames().contains(navigationPropertyName) && 
+        data != null && data.getNavigations().containsKey(navigationPropertyName)) {
+
+        EdmNavigationProperty navProp = (EdmNavigationProperty) eia.getEntityType().getProperty(navigationPropertyName);
+
+        if (navProp == null) {
+          throw new EntityProviderProducerException(EntityProviderException.EXPANDNOTSUPPORTED);
+        }
+        EntityCollection inlineData;
+        inlineData = (EntityCollection) data.getNavigation(navigationPropertyName);
+        if (inlineData == null) {
+          inlineData = new EntityCollection();
+        }
+
+        if (inlineData.getEntities().isEmpty()) {
+          return;
+        }
+        writer.writeStartElement(Edm.NAMESPACE_M_2007_08, FormatXml.M_INLINE);
+
+        EntityCollectionSerializerProperties inlineProperties = inlineData.getCollectionProperties() == null
+            ? EntityCollectionSerializerProperties.serviceRoot(data.getWriteProperties().getServiceRoot()).build()
+            : inlineData.getCollectionProperties();
+        EdmEntitySet inlineEntitySet = eia.getEntitySet().getRelatedEntitySet(navProp);
+        AtomFeedSerializer inlineFeedProducer = new AtomFeedSerializer(inlineProperties);
+        inlineData.setCollectionProperties(inlineProperties);
+        EntityInfoAggregator inlineEia =
+            EntityInfoAggregator.create(inlineEntitySet, null);
+        inlineFeedProducer.append(writer, inlineEia, inlineData, true);
+
+        writer.writeEndElement();
+
+    }
+  }
+
+  private void appendInlineEntry(final XMLStreamWriter writer, final String navigationPropertyName,
+      final EntityInfoAggregator eia, final Entity data) throws EntityProviderException,
+      XMLStreamException, EdmException {
+
+    if (data.getNavigations() != null && data.getNavigations().containsKey(navigationPropertyName)) {
+
+      EdmNavigationProperty navProp = (EdmNavigationProperty) eia.getEntityType().getProperty(navigationPropertyName);
+
+      Entity inlineData = (Entity) data.getNavigation(navigationPropertyName);
+
+      if ((inlineData == null) || inlineData.getProperties().size() == 0) {
+        return;
+      }
+
+      writer.writeStartElement(Edm.NAMESPACE_M_2007_08, FormatXml.M_INLINE);
+      if (inlineData != null && !(inlineData.getProperties().isEmpty())) {
+        inlineData.setWriteProperties(inlineData.getWriteProperties() == null ? data.getWriteProperties() : inlineData
+            .getWriteProperties());
+        EdmEntitySet inlineEntitySet = eia.getEntitySet().getRelatedEntitySet(navProp);
+        AtomEntryEntitySerializer inlineProducer = new AtomEntryEntitySerializer(inlineData.getWriteProperties());
+        EntityInfoAggregator inlineEia =
+            EntityInfoAggregator.create(inlineEntitySet, null);
+        inlineProducer.append(writer, inlineEia, inlineData, false, false);
+      }
+
+      writer.writeEndElement();
+    }
+  }
+
+
+  private void appendAtomEditLink(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+      final String selfLink) throws EntityProviderException {
+    try {
+      writer.writeStartElement(FormatXml.ATOM_LINK);
+      writer.writeAttribute(FormatXml.ATOM_HREF, selfLink);
+      writer.writeAttribute(FormatXml.ATOM_REL, Edm.LINK_REL_EDIT);
+      writer.writeAttribute(FormatXml.ATOM_TITLE, eia.getEntityType().getName());
+      writer.writeEndElement();
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    } catch (EdmException e) {
+      throw new EntityProviderProducerException(e.getMessageReference(), e);
+    }
+  }
+
+  private void appendAtomContentLink(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+      final Map<String, Object> data, final String selfLink) throws EntityProviderException, EdmException {
+    try {
+      String mediaResourceMimeType = null;
+      EdmMapping entityTypeMapping = eia.getEntityType().getMapping();
+      if (entityTypeMapping != null) {
+        String mediaResourceMimeTypeKey = entityTypeMapping.getMediaResourceMimeTypeKey();
+        if (mediaResourceMimeTypeKey != null) {
+          mediaResourceMimeType = (String) data.get(mediaResourceMimeTypeKey);
+        }
+      }
+      if (mediaResourceMimeType == null) {
+        mediaResourceMimeType = ContentType.APPLICATION_OCTET_STREAM.toString();
+      }
+
+      writer.writeStartElement(FormatXml.ATOM_LINK);
+      writer.writeAttribute(FormatXml.ATOM_HREF, selfLink + VALUE);
+      writer.writeAttribute(FormatXml.ATOM_REL, Edm.LINK_REL_EDIT_MEDIA);
+      writer.writeAttribute(FormatXml.ATOM_TYPE, mediaResourceMimeType);
+      writer.writeEndElement();
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    }
+  }
+
+  private void appendAtomContentPart(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+      final Map<String, Object> data, final String selfLink) throws EntityProviderException, EdmException {
+    try {
+
+      EdmMapping entityTypeMapping = eia.getEntityType().getMapping();
+      String self = null;
+      String mediaResourceMimeType = null;
+
+      if (entityTypeMapping != null) {
+        String mediaResourceSourceKey = entityTypeMapping.getMediaResourceSourceKey();
+        if (mediaResourceSourceKey != null) {
+          self = (String) data.get(mediaResourceSourceKey);
+        }
+        if (self == null) {
+          self = selfLink + VALUE;
+        }
+        String mediaResourceMimeTypeKey = entityTypeMapping.getMediaResourceMimeTypeKey();
+        if (mediaResourceMimeTypeKey != null) {
+          mediaResourceMimeType = (String) data.get(mediaResourceMimeTypeKey);
+        }
+        if (mediaResourceMimeType == null) {
+          mediaResourceMimeType = ContentType.APPLICATION_OCTET_STREAM.toString();
+        }
+      } else {
+        self = selfLink + VALUE;
+        mediaResourceMimeType = ContentType.APPLICATION_OCTET_STREAM.toString();
+      }
+
+      writer.writeStartElement(FormatXml.ATOM_CONTENT);
+      writer.writeAttribute(FormatXml.ATOM_TYPE, mediaResourceMimeType);
+      writer.writeAttribute(FormatXml.ATOM_SRC, self);
+      writer.writeEndElement();
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    }
+  }
+
+  private void appendAtomMandatoryParts(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+      final Map<String, Object> data) throws EntityProviderException {
+    try {
+      writer.writeStartElement(FormatXml.ATOM_ID);
+      String idlocation = properties.getServiceRoot().toASCIIString() + createSelfLink(
+          eia, data, null, properties.isKeyAutoGenerated(), true);;
+      writer.writeCharacters(idlocation);
+      writer.writeEndElement();
+
+      writer.writeStartElement(FormatXml.ATOM_TITLE);
+      writer.writeAttribute(FormatXml.ATOM_TYPE, FormatXml.ATOM_TEXT);
+      EntityPropertyInfo titleInfo = eia.getTargetPathInfo(EdmTargetPath.SYNDICATION_TITLE);
+      if (titleInfo != null) {
+        EdmSimpleType st = (EdmSimpleType) titleInfo.getType();
+        Object object = data.get(titleInfo.getName());
+        String title = null;
+        try { //NOSONAR
+          title = st.valueToString(object, EdmLiteralKind.DEFAULT, titleInfo.getFacets());
+        } catch (EdmSimpleTypeException e) {
+          throw new EntityProviderProducerException(EdmSimpleTypeException.getMessageReference(
+              e.getMessageReference()).updateContent(e.getMessageReference().getContent(), titleInfo.getName()), e);
+        }
+        if (title != null) {
+          writer.writeCharacters(title);
+        }
+      } else {
+        writer.writeCharacters(eia.getEntitySetName());
+      }
+      writer.writeEndElement();
+
+      writer.writeStartElement(FormatXml.ATOM_UPDATED);
+
+      writer.writeCharacters(getUpdatedString(eia, data));
+
+      writer.writeEndElement();
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    } catch (EdmSimpleTypeException e) {
+      throw new EntityProviderProducerException(e.getMessageReference(), e);
+    }
+  }
+
+  String getUpdatedString(final EntityInfoAggregator eia, final Map<String, Object> data)
+      throws EdmSimpleTypeException, EntityProviderProducerException {
+    Object updateDate = null;
+    EdmFacets updateFacets = null;
+    EntityPropertyInfo updatedInfo = eia.getTargetPathInfo(EdmTargetPath.SYNDICATION_UPDATED);
+    if (updatedInfo != null) {
+      updateDate = data.get(updatedInfo.getName());
+      if (updateDate != null) {
+        updateFacets = updatedInfo.getFacets();
+      }
+    }
+    if (updateDate == null) {
+      updateDate = new Date();
+    }
+    try {
+      return EdmDateTimeOffset.getInstance().valueToString(updateDate, EdmLiteralKind.DEFAULT, updateFacets);
+    } catch (final EdmSimpleTypeException e) {
+      throw new EntityProviderProducerException(
+          EdmSimpleTypeException.getMessageReference(e.getMessageReference()).
+          updateContent(e.getMessageReference().getContent(),
+              updatedInfo == null ? null : updatedInfo.getName()), e);
+    }
+  }
+
+  private String getTargetPathValue(final EntityInfoAggregator eia, final String targetPath,
+      final Map<String, Object> data) throws EntityProviderException {
+    EntityPropertyInfo info = null;
+    try {
+      info = eia.getTargetPathInfo(targetPath);
+      if (info != null) {
+        EdmSimpleType type = (EdmSimpleType) info.getType();
+        Object value = data.get(info.getName());
+        return type.valueToString(value, EdmLiteralKind.DEFAULT, info.getFacets());
+      }
+      return null;
+    } catch (final EdmSimpleTypeException e) {
+      throw new EntityProviderProducerException(
+          EdmSimpleTypeException.getMessageReference(e.getMessageReference()).
+          updateContent(e.getMessageReference().getContent(), info.getName()), e);
+    }
+  }
+
+  private void appendAtomOptionalParts(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+      final Map<String, Object> data) throws EntityProviderException {
+    try {
+      String authorEmail = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_AUTHOREMAIL, data);
+      String authorName = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_AUTHORNAME, data);
+      String authorUri = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_AUTHORURI, data);
+      if (authorEmail != null || authorName != null || authorUri != null) {
+        writer.writeStartElement(FormatXml.ATOM_AUTHOR);
+        appendAtomOptionalPart(writer, FormatXml.ATOM_AUTHOR_NAME, authorName, false);
+        appendAtomOptionalPart(writer, FormatXml.ATOM_AUTHOR_EMAIL, authorEmail, false);
+        appendAtomOptionalPart(writer, FormatXml.ATOM_AUTHOR_URI, authorUri, false);
+        writer.writeEndElement();
+      }
+
+      String summary = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_SUMMARY, data);
+      appendAtomOptionalPart(writer, FormatXml.ATOM_SUMMARY, summary, true);
+
+      String contributorName = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_CONTRIBUTORNAME, data);
+      String contributorEmail = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_CONTRIBUTOREMAIL, data);
+      String contributorUri = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_CONTRIBUTORURI, data);
+      if (contributorEmail != null || contributorName != null || contributorUri != null) {
+        writer.writeStartElement(FormatXml.ATOM_CONTRIBUTOR);
+        appendAtomOptionalPart(writer, FormatXml.ATOM_CONTRIBUTOR_NAME, contributorName, false);
+        appendAtomOptionalPart(writer, FormatXml.ATOM_CONTRIBUTOR_EMAIL, contributorEmail, false);
+        appendAtomOptionalPart(writer, FormatXml.ATOM_CONTRIBUTOR_URI, contributorUri, false);
+        writer.writeEndElement();
+      }
+
+      String rights = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_RIGHTS, data);
+      appendAtomOptionalPart(writer, FormatXml.ATOM_RIGHTS, rights, true);
+      String published = getTargetPathValue(eia, EdmTargetPath.SYNDICATION_PUBLISHED, data);
+      appendAtomOptionalPart(writer, FormatXml.ATOM_PUBLISHED, published, false);
+
+      String term = eia.getEntityType().getNamespace() + Edm.DELIMITER + eia.getEntityType().getName();
+      writer.writeStartElement(FormatXml.ATOM_CATEGORY);
+      writer.writeAttribute(FormatXml.ATOM_CATEGORY_TERM, term);
+      writer.writeAttribute(FormatXml.ATOM_CATEGORY_SCHEME, Edm.NAMESPACE_SCHEME_2007_08);
+      writer.writeEndElement();
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    } catch (EdmException e) {
+      throw new EntityProviderProducerException(e.getMessageReference(), e);
+    }
+  }
+
+  private void appendAtomOptionalPart(final XMLStreamWriter writer, final String name, final String value,
+      final boolean writeType) throws EntityProviderException {
+    try {
+      if (value != null) {
+        writer.writeStartElement(name);
+        if (writeType) {
+          writer.writeAttribute(FormatXml.ATOM_TYPE, FormatXml.ATOM_TEXT);
+        }
+        writer.writeCharacters(value);
+        writer.writeEndElement();
+      }
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    }
+  }
+
+  static String createSelfLink(final EntityInfoAggregator eia, final Map<String, Object> data, final String extension, 
+      boolean isKeyAutoGenerated, boolean isIdTag)
+      throws EntityProviderException {
+    StringBuilder sb = new StringBuilder();
+    if (!eia.isDefaultEntityContainer()) {
+      sb.append(Encoder.encode(eia.getEntityContainerName())).append(Edm.DELIMITER);
+    }
+    sb.append(Encoder.encode(eia.getEntitySetName()));
+
+    String keyValue = createEntryKey(eia, data, isKeyAutoGenerated, isIdTag);
+    if (isIdTag && isKeyAutoGenerated && "".equals(keyValue) && keyValue.length() == 0) {
+      sb.append(extension == null ? "" : ("/" + extension));
+    } else {
+      sb.append("(").append(keyValue).append(")").
+      append(extension == null ? "" : ("/" + extension));
+    }
+    return sb.toString();
+  }
+
+  private static String createEntryKey(final EntityInfoAggregator entityInfo, final Map<String, Object> data, 
+      boolean isKeyAutoGenerated, boolean isIdTag)
+      throws EntityProviderException {
+    final List<EntityPropertyInfo> keyPropertyInfos = entityInfo.getKeyPropertyInfos();
+
+    StringBuilder keys = new StringBuilder();
+    for (final EntityPropertyInfo keyPropertyInfo : keyPropertyInfos) {
+      if (keys.length() > 0) {
+        keys.append(',');
+      }
+
+      final String name = keyPropertyInfo.getName();
+      if (keyPropertyInfos.size() > 1) {
+        keys.append(Encoder.encode(name)).append('=');
+      }
+
+      final EdmSimpleType type = (EdmSimpleType) keyPropertyInfo.getType();
+      try {
+        String keyValue = null;
+        if (isKeyAutoGenerated && data.get(name) == null) {
+          if (isIdTag) {
+            keyValue = "";
+          } else {
+            Object value = fetchDefaultValue(type.getDefaultType());
+            keyValue = Encoder.encode(type.valueToString(value, EdmLiteralKind.URI,
+                keyPropertyInfo.getFacets()));
+          }
+        } else {
+          keyValue = Encoder.encode(type.valueToString(data.get(name), EdmLiteralKind.URI,
+              keyPropertyInfo.getFacets()));
+        }
+        keys.append(keyValue);
+      } catch (final EdmSimpleTypeException e) {
+        throw new EntityProviderProducerException(
+            EdmSimpleTypeException.getMessageReference(e.getMessageReference()).
+            updateContent(e.getMessageReference().getContent(), name), e);
+      }
+    }
+
+    return keys.toString();
+  }
+
+  private static Object fetchDefaultValue(Class<?> edmType) throws EntityProviderProducerException {
+    if (edmType == boolean.class || edmType == Boolean.class) {
+        return false;
+      } else if (edmType == String.class) {
+        return "A";
+      } else if (edmType == byte.class || edmType == Byte.class) {
+        return new Byte(Byte.parseByte("0"));
+      } else if (edmType == char.class) {
+        return new Character('A');
+      } else if (edmType == short.class || edmType == Short.class) {
+        return new Short(Short.parseShort("0"));
+      } else if (edmType == int.class || edmType == Integer.class) {
+        return new Integer(0);
+      } else if (edmType == long.class || edmType == Long.class) {
+        return new Long(0L);
+      } else if (edmType == float.class || edmType == Float.class) {
+        return new Float(0.0f);
+      } else if (edmType == double.class || edmType == Double.class) {
+        return new Double(0.0d);
+      } else if (edmType == BigDecimal.class) {
+        return BigDecimal.valueOf(0.0);
+      } else if (edmType == UUID.class) {
+        return UUID.fromString("0");
+      } else if (edmType == Timestamp.class) {
+        return new Timestamp(Calendar.getInstance().getTimeInMillis());
+      } else if (edmType == Calendar.class) {
+        return Calendar.getInstance();
+      } else if (edmType == byte[].class || edmType == Byte[].class) {
+        return new byte[0];
+      } else if (edmType == Date.class) {
+        return new Date();
+      } else if (edmType == BigInteger.class) {
+        return new BigInteger("0");
+      } else if (edmType == Time.class) {
+        return new Time(0L);
+      } else {
+        throw new EntityProviderProducerException(EdmSimpleTypeException.VALUE_TYPE_NOT_SUPPORTED);
+      }
+    }
+  
+  private void appendProperties(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+      final Map<String, Object> data) throws EntityProviderException {
+    try {
+      {
+        if (!data.isEmpty() && data.size() > 0) {
+          writer.writeStartElement(Edm.NAMESPACE_M_2007_08, FormatXml.M_PROPERTIES);
+          for (String propertyName : eia.getPropertyNames()) {
+            if (data.containsKey(propertyName)) {
+              appendPropertyNameValue(writer, eia, data, propertyName);
+            }
+          }
+          writer.writeEndElement();
+        }
+      }
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    }
+  }
+
+  /**
+   * @param writer
+   * @param eia
+   * @param data
+   * @param propertyName
+   * @throws EntityProviderException
+   */
+  private void appendPropertyNameValue(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+      final Map<String, Object> data, String propertyName) throws EntityProviderException {
+    EntityPropertyInfo propertyInfo = eia.getPropertyInfo(propertyName);
+    if (isNotMappedViaCustomMapping(propertyInfo)) {
+      Object value = data.get(propertyName);
+      XmlPropertyEntitySerializer aps = new XmlPropertyEntitySerializer(properties);
+      aps.append(writer, propertyInfo.getName(), propertyInfo, value);
+    }
+  }
+
+  private boolean isNotMappedViaCustomMapping(final EntityPropertyInfo propertyInfo) {
+    EdmCustomizableFeedMappings customMapping = propertyInfo.getCustomMapping();
+    if (customMapping != null && customMapping.isFcKeepInContent() != null) {
+      return customMapping.isFcKeepInContent();
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomFeedSerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomFeedSerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomFeedSerializer.java
new file mode 100644
index 0000000..8e4e615
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/AtomFeedSerializer.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * 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.odata2.client.core.ep.serializer;
+
+import java.net.URI;
+import java.util.Date;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.client.api.ep.EntityCollection;
+import org.apache.olingo.odata2.client.api.ep.EntityCollectionSerializerProperties;
+import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
+import org.apache.olingo.odata2.core.commons.Encoder;
+import org.apache.olingo.odata2.core.edm.EdmDateTimeOffset;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Serializes an ATOM feed.
+ * 
+ */
+public class AtomFeedSerializer {
+
+  private final EntityCollectionSerializerProperties properties;
+
+  /**
+   * 
+   * @param properties
+   */
+  public AtomFeedSerializer(final EntityCollectionSerializerProperties properties) {
+    this.properties = properties == null ? 
+        EntityCollectionSerializerProperties.serviceRoot(null).build() : 
+          properties;
+  }
+ 
+  /**
+   * This serializes the xml payload feed
+   * @param writer
+   * @param eia
+   * @param data
+   * @param isInline
+   * @throws EntityProviderException
+   */
+  public void append(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+      final EntityCollection data, final boolean isInline) throws EntityProviderException {
+    try {
+      if (properties.getServiceRoot() == null) {
+        throw new EntityProviderProducerException(EntityProviderException.MANDATORY_WRITE_PROPERTY);
+      }
+      
+      writer.writeStartElement(FormatXml.ATOM_FEED);
+      if (!isInline) {
+        writer.writeDefaultNamespace(Edm.NAMESPACE_ATOM_2005);
+        writer.writeNamespace(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
+        writer.writeNamespace(Edm.PREFIX_D, Edm.NAMESPACE_D_2007_08);
+        
+      }
+      writer.writeAttribute(Edm.PREFIX_XML, Edm.NAMESPACE_XML_1998, FormatXml.XML_BASE, properties.getServiceRoot()
+          .toASCIIString());
+
+      // write all atom infos (mandatory and optional)
+      appendAtomMandatoryParts(writer, eia);
+      appendAtomSelfLink(writer, eia);
+    
+
+      appendEntries(writer, eia, data);
+
+     
+
+   
+      writer.writeEndElement();
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    }
+  }
+
+  private void appendEntries(final XMLStreamWriter writer, final EntityInfoAggregator eia,
+      final EntityCollection data) throws EntityProviderException {
+    AtomEntryEntitySerializer entryProvider;
+    for (Entity singleEntryData : data.getEntities()) {
+      entryProvider = singleEntryData.getWriteProperties() == null? data.getGlobalEntityProperties() == null ?
+          new AtomEntryEntitySerializer
+          (EntitySerializerProperties.serviceRoot(data.getCollectionProperties().getServiceRoot()).build()) :
+            new AtomEntryEntitySerializer(data.getGlobalEntityProperties()):
+            new AtomEntryEntitySerializer(singleEntryData.getWriteProperties());
+       entryProvider.append(writer, eia, singleEntryData, false, true);
+    }
+  }
+
+
+  private void appendAtomSelfLink(final XMLStreamWriter writer, final EntityInfoAggregator eia)
+      throws EntityProviderException {
+
+    URI self = properties.getSelfLink();
+    String selfLink = "";
+    if (self == null) {
+      selfLink = createSelfLink(eia);
+    } else {
+      selfLink = self.toASCIIString();
+    }
+    try {
+      writer.writeStartElement(FormatXml.ATOM_LINK);
+      writer.writeAttribute(FormatXml.ATOM_HREF, selfLink);
+      writer.writeAttribute(FormatXml.ATOM_REL, Edm.LINK_REL_SELF);
+      writer.writeAttribute(FormatXml.ATOM_TITLE, eia.getEntitySetName());
+      writer.writeEndElement();
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    }
+  }
+
+  private String createSelfLink(final EntityInfoAggregator eia) {
+    StringBuilder sb = new StringBuilder();
+    if (!eia.isDefaultEntityContainer()) {
+      final String entityContainerName = Encoder.encode(eia.getEntityContainerName());
+      sb.append(entityContainerName).append(Edm.DELIMITER);
+    }
+    final String entitySetName = Encoder.encode(eia.getEntitySetName());
+    sb.append(entitySetName);
+    return sb.toString();
+  }
+
+  private void appendAtomMandatoryParts(final XMLStreamWriter writer, final EntityInfoAggregator eia)
+      throws EntityProviderException {
+    try {
+      writer.writeStartElement(FormatXml.ATOM_ID);
+      writer.writeCharacters(createAtomId(eia));
+      writer.writeEndElement();
+
+      writer.writeStartElement(FormatXml.ATOM_TITLE);
+      writer.writeAttribute(FormatXml.M_TYPE, FormatXml.ATOM_TEXT);
+      writer.writeCharacters(eia.getEntitySetName());
+      writer.writeEndElement();
+
+      writer.writeStartElement(FormatXml.ATOM_UPDATED);
+
+      Object updateDate = null;
+      EdmFacets updateFacets = null;
+      updateDate = new Date();
+      writer.writeCharacters(EdmDateTimeOffset.getInstance().valueToString(updateDate, EdmLiteralKind.DEFAULT,
+          updateFacets));
+      writer.writeEndElement();
+
+      writer.writeStartElement(FormatXml.ATOM_AUTHOR);
+      writer.writeStartElement(FormatXml.ATOM_AUTHOR_NAME);
+      writer.writeEndElement();
+      writer.writeEndElement();
+
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    } catch (EdmSimpleTypeException e) {
+      throw new EntityProviderProducerException(e.getMessageReference(), e);
+    }
+  }
+
+  private String createAtomId(final EntityInfoAggregator eia) throws EntityProviderException {
+    return properties.getServiceRoot() + createSelfLink(eia);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonEntryEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonEntryEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonEntryEntitySerializer.java
new file mode 100644
index 0000000..b727538
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonEntryEntitySerializer.java
@@ -0,0 +1,309 @@
+/*******************************************************************************
+ * 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.odata2.client.core.ep.serializer;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmMapping;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.client.api.ep.EntityCollection;
+import org.apache.olingo.odata2.client.api.ep.EntityCollectionSerializerProperties;
+import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
+import org.apache.olingo.odata2.core.commons.ContentType;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.util.FormatJson;
+import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
+
+/**
+ * Producer for writing an entity in JSON, also usable for function imports
+ * returning a single instance of an entity type.
+ * 
+ */
+public class JsonEntryEntitySerializer {
+
+  private final EntitySerializerProperties properties;
+  private String location;
+  private String idlocation;
+  private JsonStreamWriter jsonStreamWriter;
+  private static final String VALUE = "/$value";
+
+  /**
+   * 
+   * @param properties
+   * @throws EntityProviderException
+   */
+  public JsonEntryEntitySerializer(final EntitySerializerProperties properties) {
+    this.properties = properties == null ? EntitySerializerProperties.serviceRoot(null).build() : properties;
+  }
+
+  /**
+   * This serializes the json payload entry
+   * @param writer
+   * @param entityInfo
+   * @param data
+   * @param isRootElement
+   * @throws EntityProviderException
+   */
+  public void append(final Writer writer, final EntityInfoAggregator entityInfo, final Entity data) 
+      throws EntityProviderException {
+   if (data == null) {
+     throw new EntityProviderException(EntityProviderException.NULL_VALUE);
+   }
+    final EdmEntityType type = entityInfo.getEntityType();
+
+    try {
+      jsonStreamWriter = new JsonStreamWriter(writer);
+     
+      jsonStreamWriter.beginObject();
+
+      boolean containsMetadata = false;
+      if (properties.isIncludeMetadata()) {
+        writeMetadata(entityInfo, data.getProperties(), type);
+        containsMetadata = true;
+      } 
+      writeProperties(entityInfo, data.getProperties(), type, containsMetadata);
+
+      writeNavigationProperties(writer, entityInfo, data.getNavigations(), type);
+      jsonStreamWriter.endObject();
+      
+      writer.flush();
+
+    } catch (final IOException e) {
+      throw new EntityProviderProducerException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+          .getSimpleName()), e);
+    } catch (final EdmException e) {
+      throw new EntityProviderProducerException(e.getMessageReference(), e);
+    }
+  }
+
+  private void writeNavigationProperties(final Writer writer, final EntityInfoAggregator entityInfo,
+      final Map<String, Object> data,
+      final EdmEntityType type) throws EdmException, EntityProviderException, IOException {
+    for (final String navigationPropertyName : type.getNavigationPropertyNames()) {
+      if (data.containsKey(navigationPropertyName)) {
+        if (data.get(navigationPropertyName) == null) {
+          throw new EntityProviderException(EntityProviderException.NULL_VALUE);
+        }
+        if (data.get(navigationPropertyName) instanceof Entity || 
+            data.get(navigationPropertyName) instanceof EntityCollection) {
+          jsonStreamWriter.separator();
+          jsonStreamWriter.name(navigationPropertyName);
+          writeExpandedNavigationProperty(writer, entityInfo, data, type, navigationPropertyName);
+        } else if (data.get(navigationPropertyName) instanceof Map<?,?>){
+          writeNavigationLinks(entityInfo, data);
+        } else {
+          throw new EntityProviderException(EntityProviderException.INCORRECT_NAVIGATION_TYPE);
+        }
+      }
+    }
+  }
+
+  private void writeExpandedNavigationProperty(final Writer writer, final EntityInfoAggregator entityInfo,
+      final Map<String, Object> data,
+      final EdmEntityType type, final String navigationPropertyName) throws EdmException, EntityProviderException,
+      IOException {
+    
+    final EdmNavigationProperty navigationProperty = (EdmNavigationProperty) type.getProperty(navigationPropertyName);
+    final boolean isFeed = navigationProperty.getMultiplicity() == EdmMultiplicity.MANY;
+    final EdmEntitySet entitySet = entityInfo.getEntitySet();
+    final EdmEntitySet inlineEntitySet = entitySet.getRelatedEntitySet(navigationProperty);
+
+    if (isFeed) {
+      EntityCollection inlineData = (EntityCollection) data.get(navigationProperty.getName());
+      
+      if(inlineData == null){
+        throw new EntityProviderException(EntityProviderException.NULL_VALUE);
+      }
+      final EntityCollectionSerializerProperties inlineProperties = inlineData.getCollectionProperties() == null ? 
+          EntityCollectionSerializerProperties.
+          serviceRoot(properties.getServiceRoot()).build() : 
+            inlineData.getCollectionProperties();
+      JsonFeedEntitySerializer jsonFeedEntityProducer = new JsonFeedEntitySerializer(inlineProperties);
+      final EntityInfoAggregator inlineEntityInfo =
+          EntityInfoAggregator.create(inlineEntitySet, null);
+      jsonFeedEntityProducer.appendAsArray(writer, inlineEntityInfo, inlineData);
+    } else {
+      Entity inlineData = (Entity) data.get(navigationProperty.getName());
+    //This statement is used for the client use case. Flag should never be set on server side
+      if(inlineData == null){
+        throw new EntityProviderException(EntityProviderException.NULL_VALUE);
+      }
+      if (inlineData != null && inlineData.getProperties() != null && 
+          !inlineData.getProperties().isEmpty()) {
+        final EntitySerializerProperties inlineProperties = inlineData.getWriteProperties() == null ?
+            EntitySerializerProperties.
+            serviceRoot(properties.getServiceRoot()).build() : inlineData.getWriteProperties();
+        final EntityInfoAggregator inlineEntityInfo =
+            EntityInfoAggregator.create(inlineEntitySet, null);
+        new JsonEntryEntitySerializer(inlineProperties).append(writer, inlineEntityInfo, inlineData);
+      } else {
+        jsonStreamWriter.beginObject();
+        jsonStreamWriter.endObject();
+      }
+    }
+   }
+
+  private void writeProperties(final EntityInfoAggregator entityInfo, final Map<String, Object> data,
+      final EdmEntityType type, boolean containsMetadata) throws EdmException, EntityProviderException, IOException {
+    // if the payload contains metadata we must not omit the first comm as it separates the _metadata object form the
+    // properties
+    boolean omitComma = !containsMetadata;
+
+    List<String> propertyNames = type.getPropertyNames();
+    for (final String propertyName : propertyNames) {
+      if (data.containsKey(propertyName)) {
+        omitComma = appendPropertyNameValue(entityInfo, data, omitComma, propertyName);
+      } 
+    }
+  }
+
+  /**
+   * @param entityInfo
+   * @param data
+   * @param omitComma
+   * @param propertyName
+   * @return
+   * @throws IOException
+   * @throws EdmException
+   * @throws EntityProviderException
+   */
+  private boolean appendPropertyNameValue(final EntityInfoAggregator entityInfo, final Map<String, Object> data,
+      boolean omitComma, String propertyName) throws IOException, EdmException, EntityProviderException {
+    if (omitComma) {
+      omitComma = false; //NOSONAR
+    } else {
+      jsonStreamWriter.separator();
+    }
+    jsonStreamWriter.name(propertyName);
+ 
+    JsonPropertyEntitySerializer.appendPropertyValue(jsonStreamWriter,
+        entityInfo.getPropertyInfo(propertyName),
+        data.get(propertyName),
+        properties.isValidatingFacets());
+    return omitComma;
+  }
+  
+  private void writeMetadata(final EntityInfoAggregator entityInfo, final Map<String, Object> data,
+      final EdmEntityType type) throws IOException, EntityProviderException, EdmException {
+    if (properties.getServiceRoot() == null) {
+      location = "";
+      idlocation = "";
+    } else {
+      location = properties.getServiceRoot().toASCIIString() +
+          AtomEntryEntitySerializer.createSelfLink(entityInfo, data, null, properties.isKeyAutoGenerated(), false);
+      idlocation = properties.getServiceRoot().toASCIIString() +
+          AtomEntryEntitySerializer.createSelfLink(entityInfo, data, null, properties.isKeyAutoGenerated(), true);
+    }
+
+    jsonStreamWriter.name(FormatJson.METADATA);
+    jsonStreamWriter.beginObject();
+    jsonStreamWriter.namedStringValue(FormatJson.ID, idlocation);
+    jsonStreamWriter.separator();
+    jsonStreamWriter.namedStringValue(FormatJson.URI, location);
+    jsonStreamWriter.separator();
+    jsonStreamWriter.namedStringValueRaw(FormatJson.TYPE, type.getNamespace() + Edm.DELIMITER + type.getName());
+    
+    if (type.hasStream()) {
+      jsonStreamWriter.separator();
+
+      EdmMapping entityTypeMapping = entityInfo.getEntityType().getMapping();
+      String mediaResourceMimeType = null;
+      String mediaSrc = null;
+
+      if (entityTypeMapping != null) {
+        String mediaResourceSourceKey = entityTypeMapping.getMediaResourceSourceKey();
+        if (mediaResourceSourceKey != null) {
+          mediaSrc = (String) data.get(mediaResourceSourceKey);
+        }
+        if (mediaSrc == null) {
+          mediaSrc = location + VALUE;
+        }
+        String mediaResourceMimeTypeKey = entityTypeMapping.getMediaResourceMimeTypeKey();
+        if (mediaResourceMimeTypeKey != null) {
+          mediaResourceMimeType = (String) data.get(mediaResourceMimeTypeKey);
+        }
+        if (mediaResourceMimeType == null) {
+          mediaResourceMimeType = ContentType.APPLICATION_OCTET_STREAM.toString();
+        }
+      } else {
+        mediaSrc = location + VALUE;
+        mediaResourceMimeType = ContentType.APPLICATION_OCTET_STREAM.toString();
+      }
+
+      jsonStreamWriter.namedStringValueRaw(FormatJson.CONTENT_TYPE, mediaResourceMimeType);
+      jsonStreamWriter.separator();
+
+      jsonStreamWriter.namedStringValue(FormatJson.MEDIA_SRC, mediaSrc);
+      jsonStreamWriter.separator();
+      jsonStreamWriter.namedStringValue(FormatJson.EDIT_MEDIA, location + VALUE);
+    }
+    jsonStreamWriter.endObject();
+  }
+
+  private String createCustomTargetLink(final EntityInfoAggregator entityInfo, final String navigationPropertyName,
+      final Map<String, Object> key) throws EntityProviderException, EdmException {
+    String target;
+    final EntityInfoAggregator targetEntityInfo = EntityInfoAggregator.create(
+        entityInfo.getEntitySet().getRelatedEntitySet(
+            (EdmNavigationProperty) entityInfo.getEntityType().getProperty(navigationPropertyName)));
+    target = (properties.getServiceRoot() == null ? "" : properties.getServiceRoot().toASCIIString())
+        + AtomEntryEntitySerializer.createSelfLink(targetEntityInfo, key, null, properties.isKeyAutoGenerated(), false);
+    return target;
+  }
+
+  private void writeNavigationLinks(final EntityInfoAggregator entityInfo,
+      Map<String, Object> navigationLinks) throws IOException, 
+  EntityProviderException, EdmException {
+    if (navigationLinks != null && !navigationLinks.isEmpty()) {
+      for (Entry<String, Object> entry : navigationLinks.entrySet()) {
+        String target = null;
+        if (entry.getValue() instanceof HashMap<?, ?>) {
+          @SuppressWarnings("unchecked")
+          Map<String, Object> navigationKeyMap = (Map<String, Object>) entry.getValue();
+          if (navigationKeyMap != null && !navigationKeyMap.isEmpty()) { //NOSONAR
+            target = createCustomTargetLink(entityInfo, entry.getKey(), navigationKeyMap);
+            jsonStreamWriter.separator();
+            jsonStreamWriter.name(entry.getKey());
+            jsonStreamWriter.beginObject()
+                .name(FormatJson.DEFERRED);
+            JsonLinkEntitySerializer.appendUri(jsonStreamWriter, target);
+            jsonStreamWriter.endObject();
+          }
+        }
+      }
+    }
+  }
+
+  public String getLocation() {
+    return location;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonFeedEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonFeedEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonFeedEntitySerializer.java
new file mode 100644
index 0000000..e86b6c4
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonFeedEntitySerializer.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * 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.odata2.client.core.ep.serializer;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.client.api.ep.EntityCollection;
+import org.apache.olingo.odata2.client.api.ep.EntityCollectionSerializerProperties;
+import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.util.FormatJson;
+import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
+
+/**
+ * Producer for writing an entity collection (a feed) in JSON.
+ * 
+ */
+public class JsonFeedEntitySerializer {
+
+  private final EntityCollectionSerializerProperties properties;
+
+  /**
+   * 
+   * @param properties
+   * @throws EntityProviderException
+   */
+  public JsonFeedEntitySerializer(final EntityCollectionSerializerProperties properties) {
+    this.properties = properties == null ? EntityCollectionSerializerProperties.
+        serviceRoot(null).build() : properties;
+  }
+
+  /**
+   * This serializes the json payload feed
+   * @param writer
+   * @param entityInfo
+   * @param data
+   * @throws EntityProviderException
+   */
+  public void appendAsArray(final Writer writer, final EntityInfoAggregator entityInfo,
+                            final EntityCollection data) throws EntityProviderException {
+    
+    JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+    try {
+      jsonStreamWriter.beginArray();
+      appendEntries(writer, entityInfo, data, jsonStreamWriter);
+      jsonStreamWriter.endArray();
+    } catch (final IOException e) {
+      throw new EntityProviderProducerException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+          .getSimpleName()), e);
+    }
+  }
+
+  /**
+   * This serializes the json payload feed
+   * @param writer
+   * @param entityInfo
+   * @param data
+   * @param isRootElement
+   * @throws EntityProviderException
+   */
+  public void appendAsObject(final Writer writer, final EntityInfoAggregator entityInfo,
+      final EntityCollection data) throws EntityProviderException {
+    if (data == null) {
+      throw new EntityProviderException(EntityProviderException.NULL_VALUE);
+    }
+    JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+
+    try {
+      jsonStreamWriter.beginObject();
+
+      jsonStreamWriter.name(FormatJson.RESULTS)
+          .beginArray();
+
+      appendEntries(writer, entityInfo, data, jsonStreamWriter);
+
+      jsonStreamWriter.endArray();
+
+      jsonStreamWriter.endObject();
+    } catch (final IOException e) {
+      throw new EntityProviderProducerException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+          .getSimpleName()), e);
+    }
+  }
+  
+  private void appendEntries(final Writer writer, final EntityInfoAggregator entityInfo,
+      final EntityCollection data, JsonStreamWriter jsonStreamWriter) throws EntityProviderException,
+      IOException {
+    boolean first = true;
+    for (Entity entryData : data.getEntities()) {
+      if (first) {
+        first = false;
+      } else {
+        jsonStreamWriter.separator();
+      }
+      EntitySerializerProperties entryProperties = entryData == null ||
+          entryData.getWriteProperties() == null ? data.getGlobalEntityProperties() != null?
+              data.getGlobalEntityProperties(): EntitySerializerProperties.
+              serviceRoot(properties.getServiceRoot()).
+              build() : entryData.getWriteProperties();
+      
+      JsonEntryEntitySerializer entryProducer = new JsonEntryEntitySerializer(entryProperties);
+      entryProducer.append(writer, entityInfo, entryData);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonLinkEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonLinkEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonLinkEntitySerializer.java
new file mode 100644
index 0000000..cd756ce
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonLinkEntitySerializer.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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.odata2.client.core.ep.serializer;
+
+import java.io.IOException;
+
+import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
+import org.apache.olingo.odata2.core.ep.util.FormatJson;
+import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
+
+/**
+ * Producer for writing a link in JSON.
+ * 
+ */
+public class JsonLinkEntitySerializer {
+
+  private final EntityProviderWriteProperties properties; //NOSONAR
+
+  /**
+   * 
+   * @param properties
+   * @throws EntityProviderException
+   */
+  public JsonLinkEntitySerializer(final EntityProviderWriteProperties properties) {
+    this.properties = properties == null ? EntityProviderWriteProperties.serviceRoot(null).build() : properties;
+  }
+
+  protected static void appendUri(final JsonStreamWriter jsonStreamWriter, final String uri) throws IOException {
+    jsonStreamWriter.beginObject()
+        .namedStringValue(FormatJson.URI, uri)
+        .endObject();
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonPropertyEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonPropertyEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonPropertyEntitySerializer.java
new file mode 100644
index 0000000..f759389
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/JsonPropertyEntitySerializer.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * 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.odata2.client.core.ep.serializer;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityComplexPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.util.FormatJson;
+import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
+
+/**
+ * Producer for writing a single simple or complex property in JSON, also usable
+ * for function imports returning a single instance of a simple or complex type.
+ * 
+ */
+public class JsonPropertyEntitySerializer {
+
+  /**
+   * Serializes a property of every entry in json payload
+   * @param writer
+   * @param propertyInfo
+   * @param value
+   * @throws EntityProviderException
+   */
+  public void append(final Writer writer, final EntityPropertyInfo propertyInfo, final Object value)
+      throws EntityProviderException {
+    JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+
+    try {
+      jsonStreamWriter.beginObject()
+          .name(FormatJson.D)
+          .beginObject();
+
+      jsonStreamWriter.name(propertyInfo.getName());
+      appendPropertyValue(jsonStreamWriter, propertyInfo.isComplex() ? (EntityComplexPropertyInfo) propertyInfo
+          : propertyInfo, value, true);
+
+      jsonStreamWriter.endObject()
+          .endObject();
+    } catch (final IOException e) {
+      throw new EntityProviderProducerException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass()
+          .getSimpleName()), e);
+    } catch (final EdmException e) {
+      throw new EntityProviderProducerException(e.getMessageReference(), e);
+    }
+  }
+
+  protected static void appendPropertyValue(final JsonStreamWriter jsonStreamWriter,
+                                            final EntityPropertyInfo propertyInfo, final Object value,
+                                            boolean validatingFacets) throws IOException, EdmException,
+      EntityProviderException { //NOSONAR
+    if (propertyInfo.isComplex()) {
+      if (value == null || value instanceof Map<?,?>) {
+        jsonStreamWriter.beginObject();
+        appendPropertyMetadata(jsonStreamWriter, propertyInfo.getType());
+        if (value == null) {
+          jsonStreamWriter.endObject();
+          return;
+        }
+        for (final EntityPropertyInfo childPropertyInfo : ((EntityComplexPropertyInfo) propertyInfo)
+            .getPropertyInfos()) {
+          final String name = childPropertyInfo.getName();
+          if ( !((Map<?,?>)value).containsKey(name)) { //NOSONAR
+            continue;
+          } 
+          jsonStreamWriter.separator();
+          jsonStreamWriter.name(name);
+          appendPropertyValue(jsonStreamWriter, childPropertyInfo,
+              value == null ? null : ((Map<?,?>) value).get(name), validatingFacets); //NOSONAR
+        }
+        jsonStreamWriter.endObject();
+      } else {
+        throw new EntityProviderProducerException(EntityProviderException.ILLEGAL_ARGUMENT
+            .addContent("A complex property must have a Map as data"));
+      }
+    } else {
+      final EdmSimpleType type = (EdmSimpleType) propertyInfo.getType();
+      final Object contentValue = value instanceof Entity ? ((Entity) value).
+          getProperties().get(propertyInfo.getName()) : value;
+      final EdmFacets facets = validatingFacets ? propertyInfo.getFacets(): null;
+      String valueAsString = null;
+      try {
+      valueAsString = type.valueToString(contentValue, EdmLiteralKind.JSON, facets);
+      } catch (EdmSimpleTypeException e) {
+        throw new EntityProviderProducerException(EdmSimpleTypeException.getMessageReference(
+            e.getMessageReference()).updateContent(e.getMessageReference().getContent(), 
+                propertyInfo.getName()), e);
+      }
+      switch (EdmSimpleTypeKind.valueOf(type.getName())) {
+      case String:
+        jsonStreamWriter.stringValue(valueAsString);
+        break;
+      case Boolean:
+      case Byte:
+      case SByte:
+      case Int16:
+      case Int32:
+        jsonStreamWriter.unquotedValue(valueAsString);
+        break;
+      case DateTime:
+      case DateTimeOffset:
+        // Although JSON escaping is (and should be) done in the JSON
+        // serializer, we backslash-escape the forward slash here explicitly
+        // because it is not required to escape it in JSON but in OData.
+        jsonStreamWriter.stringValueRaw(valueAsString == null ? null : valueAsString.replace("/", "\\/"));
+        break;
+      default:
+        jsonStreamWriter.stringValueRaw(valueAsString);
+        break;
+      }
+    }
+  }
+
+  protected static void appendPropertyMetadata(final JsonStreamWriter jsonStreamWriter, final EdmType type)
+      throws IOException, EdmException {
+    jsonStreamWriter.name(FormatJson.METADATA)
+        .beginObject()
+        .namedStringValueRaw(FormatJson.TYPE, type.getNamespace() + Edm.DELIMITER + type.getName())
+        .endObject();
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/XmlPropertyEntitySerializer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/XmlPropertyEntitySerializer.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/XmlPropertyEntitySerializer.java
new file mode 100644
index 0000000..24bfc17
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/serializer/XmlPropertyEntitySerializer.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.odata2.client.core.ep.serializer;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmCustomizableFeedMappings;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.Entity;
+import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
+import org.apache.olingo.odata2.core.ep.EntityProviderProducerException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityComplexPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Internal EntityProvider for simple and complex EDM properties which are pre-analyzed as {@link EntityPropertyInfo}.
+ * 
+ */
+public class XmlPropertyEntitySerializer {
+
+  private final boolean validateFacets;
+
+  /**
+   * 
+   * @param writeProperties
+   */
+  public XmlPropertyEntitySerializer(final EntitySerializerProperties writeProperties) {
+    this(writeProperties.isValidatingFacets());
+  }
+
+  /**
+   * 
+   * @param validateFacets
+   */
+  public XmlPropertyEntitySerializer( final boolean validateFacets) {
+    this.validateFacets = validateFacets;
+  }
+
+  /**
+   * Append {@link Object} <code>value</code> based on {@link EntityPropertyInfo} to {@link XMLStreamWriter} in an
+   * already existing XML structure inside the d namespace.
+   * 
+   * @param writer
+   * @param name Name of the outer XML tag
+   * @param propertyInfo
+   * @param value
+   * @throws EntityProviderException
+   */
+  public void append(final XMLStreamWriter writer, final String name, final EntityPropertyInfo propertyInfo,
+      final Object value) throws EntityProviderException {
+    try {
+      writer.writeStartElement(Edm.NAMESPACE_D_2007_08, name);
+
+      if (propertyInfo.isComplex()) {
+        appendProperty(writer, (EntityComplexPropertyInfo) propertyInfo, value);
+      } else {
+        appendProperty(writer, propertyInfo, value);
+      }
+
+      writer.writeEndElement();
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    } catch (EdmException e) {
+      throw new EntityProviderProducerException(e.getMessageReference(), e);
+    }
+  }
+
+  /**
+   * Serializes custom properties
+   * @param writer
+   * @param name
+   * @param propertyInfo
+   * @param value
+   * @throws EntityProviderException
+   */
+  public void appendCustomProperty(final XMLStreamWriter writer, final String name,
+      final EntityPropertyInfo propertyInfo, final Object value) throws EntityProviderException {
+    try {
+      if (!propertyInfo.isComplex()) {
+        writeStartElementWithCustomNamespace(writer, propertyInfo, name);
+        appendProperty(writer, propertyInfo, value);
+        writer.writeEndElement();
+      }
+    } catch (XMLStreamException e) {
+      throw new EntityProviderProducerException(EntityProviderException.COMMON, e);
+    } catch (EdmException e) {
+      throw new EntityProviderProducerException(e.getMessageReference(), e);
+    }
+  }
+
+  
+  /**
+   * 
+   * @param writer
+   * @param propertyInfo
+   * @param value
+   * @throws XMLStreamException
+   * @throws EdmException
+   * @throws EntityProviderException
+   */
+  private void appendProperty(final XMLStreamWriter writer, final EntityComplexPropertyInfo propertyInfo,
+      final Object value) throws XMLStreamException, EdmException, EntityProviderException {
+
+    if (value == null) {
+      writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.ATOM_NULL, FormatXml.ATOM_VALUE_TRUE);
+    } else {
+      writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.ATOM_TYPE, getFqnTypeName(propertyInfo));
+      List<EntityPropertyInfo> propertyInfos = propertyInfo.getPropertyInfos();
+      for (EntityPropertyInfo childPropertyInfo : propertyInfos) {
+        if ( value instanceof Map && !((Map<?,?>)value).containsKey(childPropertyInfo.getName())||
+            (value instanceof Entity && (((Entity)value).getProperty(childPropertyInfo.getName()))==null)) {
+          continue;
+        }
+        Object childValue = extractChildValue(value, childPropertyInfo.getName());
+        append(writer, childPropertyInfo.getName(), childPropertyInfo, childValue);
+      }
+    }
+  }
+
+  /**
+   * Returns full qualified name of a type of a given PropertyInfo.
+   * @return Full qualified name
+   */
+  private String getFqnTypeName(final EntityComplexPropertyInfo propertyInfo) throws EdmException {
+    return propertyInfo.getType().getNamespace() + Edm.DELIMITER + propertyInfo.getType().getName();
+  }
+
+  /**
+   * If <code>value</code> is a {@link Map} the element with given <code>name</code> as key is returned.
+   * If <code>value</code> is NOT a {@link Map} its {@link String#valueOf(Object)} result is returned.
+   * 
+   * @param value
+   * @param name
+   * @return name or result (see above)
+   */
+  private Object extractChildValue(final Object value, final String name) {
+    if (value instanceof Map) {
+      Map<?, ?> map = (Map<?, ?>) value;
+      return map.get(name);
+    }else if (value instanceof Entity) {
+      Map<?, ?> map = ((Entity) value).getProperties();
+      return map.get(name);
+    }
+    return String.valueOf(value);
+  }
+
+  /**
+   * Appends a simple-property value to the XML stream.
+   * @param writer the XML stream writer
+   * @param prop property informations
+   * @param value the value of the property
+   * @throws XMLStreamException
+   * @throws EdmException
+   * @throws EntityProviderProducerException 
+   */
+  private void appendProperty(final XMLStreamWriter writer, final EntityPropertyInfo prop, final Object value)
+      throws XMLStreamException, EdmException, EntityProviderProducerException {
+    Object contentValue = value;
+    String mimeType = null;
+    if (prop.getMimeType() != null) {
+      mimeType = prop.getMimeType();
+    } else if (prop.getMapping() != null && prop.getMapping().getMediaResourceMimeTypeKey() != null) {
+      mimeType = (String) extractChildValue(value, prop.getMapping().getMediaResourceMimeTypeKey());
+      contentValue = extractChildValue(value, prop.getName());
+    }
+
+    if (mimeType != null) {
+      writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.M_MIME_TYPE, mimeType);
+    }
+
+    final EdmSimpleType type = (EdmSimpleType) prop.getType();
+    final EdmFacets facets = validateFacets ? prop.getFacets() : null;
+    String valueAsString = null;
+    try {
+      valueAsString = type.valueToString(contentValue, EdmLiteralKind.DEFAULT, facets);
+    } catch (EdmSimpleTypeException e) {
+        throw new EntityProviderProducerException(EdmSimpleTypeException.getMessageReference(
+            e.getMessageReference()).updateContent(
+                e.getMessageReference().getContent(), prop.getName()), e);
+    }
+    if (valueAsString == null) {
+      writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.ATOM_NULL, FormatXml.ATOM_VALUE_TRUE);
+    } else {
+      writer.writeCharacters(valueAsString);
+    }
+  }
+
+  /**
+   * 
+   * @param writer
+   * @param prop
+   * @param name
+   * @throws XMLStreamException
+   * @throws EntityProviderException
+   */
+  private void writeStartElementWithCustomNamespace(final XMLStreamWriter writer, final EntityPropertyInfo prop,
+      final String name) throws XMLStreamException, EntityProviderException {
+    EdmCustomizableFeedMappings mapping = prop.getCustomMapping();
+    String nsPrefix = mapping.getFcNsPrefix();
+    String nsUri = mapping.getFcNsUri();
+    if (nsUri == null || nsPrefix == null) {
+      throw new EntityProviderProducerException(EntityProviderException.INVALID_NAMESPACE.addContent(name));
+    }
+    writer.writeStartElement(nsPrefix, name, nsUri);
+    writer.writeNamespace(nsPrefix, nsUri);
+  }
+}