You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2016/03/04 21:36:58 UTC

[15/39] olingo-odata4 git commit: OLINGO-878: Adding support to remove unvalid xml characters from Atom payload

OLINGO-878: Adding support to remove unvalid xml characters from Atom payload


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

Branch: refs/heads/OLINGO-856_ODataHandlerInAPI
Commit: d880d6c48058d9413bb914a5bd3c13f70a9db323
Parents: 3c205f9
Author: Ramesh Reddy <ra...@jboss.org>
Authored: Thu Feb 11 14:12:47 2016 -0600
Committer: Ramesh Reddy <ra...@jboss.org>
Committed: Fri Feb 12 19:37:58 2016 -0600

----------------------------------------------------------------------
 .../serializer/ComplexSerializerOptions.java    |  14 +-
 .../EntityCollectionSerializerOptions.java      |  14 +-
 .../api/serializer/EntitySerializerOptions.java |  14 +-
 .../serializer/PrimitiveSerializerOptions.java  |  13 ++
 .../PrimitiveValueSerializerOptions.java        |  14 +-
 .../olingo/server/core/MetadataParser.java      | 199 +++++++++++++++----
 .../server/core/SchemaBasedEdmProvider.java     |  86 +++-----
 .../olingo/server/core/ServiceRequest.java      |  50 ++++-
 .../server/core/requests/DataRequest.java       |  13 +-
 .../src/main/resources/org.apache.olingo.v1.xml |  40 ++++
 .../core/MetadataParserAnnotationsTest.java     |   2 +-
 .../olingo/server/core/MetadataParserTest.java  |   1 -
 .../server/core/ServiceDispatcherTest.java      |   3 +
 .../server/example/TripPinServiceTest.java      |  25 ++-
 .../olingo/server/example/TripPinServlet.java   |   3 +-
 .../src/test/resources/airlines.json            |   2 +-
 .../src/test/resources/annotations.xml          |   3 +
 .../src/test/resources/trippin.xml              |   6 +-
 .../core/serializer/xml/ODataXmlSerializer.java | 138 +++++++++----
 .../serializer/xml/ODataXmlSerializerTest.java  |  27 ++-
 20 files changed, 498 insertions(+), 169 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ComplexSerializerOptions.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ComplexSerializerOptions.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ComplexSerializerOptions.java
index d6788e5..179c4d4 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ComplexSerializerOptions.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ComplexSerializerOptions.java
@@ -28,6 +28,7 @@ public class ComplexSerializerOptions {
   private ContextURL contextURL;
   private ExpandOption expand;
   private SelectOption select;
+  private String xml10InvalidCharReplacement;
 
   /** Gets the {@link ContextURL}. */
   public ContextURL getContextURL() {
@@ -44,6 +45,11 @@ public class ComplexSerializerOptions {
     return select;
   }
 
+  /** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
+  public String xml10InvalidCharReplacement() {
+    return xml10InvalidCharReplacement;
+  }  
+
   private ComplexSerializerOptions() {}
 
   /** Initializes the options builder. */
@@ -77,7 +83,13 @@ public class ComplexSerializerOptions {
       options.select = select;
       return this;
     }
-
+    
+    /** set the replacement string for xml 1.0 unicode controlled characters that are not allowed */
+    public Builder xml10InvalidCharReplacement(final String replacement) {
+      options.xml10InvalidCharReplacement = replacement;
+      return this;
+    } 
+    
     /** Builds the OData serializer options. */
     public ComplexSerializerOptions build() {
       return options;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
index 611485f..9ee7d24 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
@@ -32,6 +32,7 @@ public class EntityCollectionSerializerOptions {
   private SelectOption select;
   private boolean writeOnlyReferences;
   private String id;
+  private String xml10InvalidCharReplacement;
 
   /** Gets the {@link ContextURL}. */
   public ContextURL getContextURL() {
@@ -63,6 +64,11 @@ public class EntityCollectionSerializerOptions {
     return id;
   }
 
+  /** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
+  public String xml10InvalidCharReplacement() {
+    return xml10InvalidCharReplacement;
+  }  
+
   /** Initializes the options builder. */
   public static Builder with() {
     return new Builder();
@@ -112,7 +118,13 @@ public class EntityCollectionSerializerOptions {
       options.id = id;
       return this;
     }
-
+    
+    /** set the replacement String for xml 1.0 unicode controlled characters that are not allowed */
+    public Builder xml10InvalidCharReplacement(final String replacement) {
+      options.xml10InvalidCharReplacement = replacement;
+      return this;
+    } 
+    
     /** Builds the OData serializer options. */
     public EntityCollectionSerializerOptions build() {
       return options;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntitySerializerOptions.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntitySerializerOptions.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntitySerializerOptions.java
index 16481a2..e244660 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntitySerializerOptions.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntitySerializerOptions.java
@@ -28,6 +28,7 @@ public class EntitySerializerOptions {
   private ExpandOption expand;
   private SelectOption select;
   private boolean writeOnlyReferences;
+  private String xml10InvalidCharReplacement;
 
   /** Gets the {@link ContextURL}. */
   public ContextURL getContextURL() {
@@ -49,6 +50,11 @@ public class EntitySerializerOptions {
     return writeOnlyReferences;
   }
 
+  /** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
+  public String xml10InvalidCharReplacement() {
+    return xml10InvalidCharReplacement;
+  }  
+
   private EntitySerializerOptions() {}
 
   /** Initializes the options builder. */
@@ -88,7 +94,13 @@ public class EntitySerializerOptions {
       options.writeOnlyReferences = ref;
       return this;
     }
-
+    
+    /** set the replacement string for xml 1.0 unicode controlled characters that are not allowed */
+    public Builder xml10InvalidCharReplacement(final String replacement) {
+      options.xml10InvalidCharReplacement = replacement;
+      return this;
+    } 
+    
     /** Builds the OData serializer options. */
     public EntitySerializerOptions build() {
       return options;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/PrimitiveSerializerOptions.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/PrimitiveSerializerOptions.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/PrimitiveSerializerOptions.java
index 1de20d8..61a3160 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/PrimitiveSerializerOptions.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/PrimitiveSerializerOptions.java
@@ -30,6 +30,7 @@ public final class PrimitiveSerializerOptions {
   private Integer precision;
   private Integer scale;
   private Boolean isUnicode;
+  private String xml10InvalidCharReplacement;
 
   /** Gets the {@link ContextURL}. */
   public ContextURL getContextURL() {
@@ -60,6 +61,12 @@ public final class PrimitiveSerializerOptions {
   public Boolean isUnicode() {
     return isUnicode;
   }
+  
+  /** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
+  public String xml10InvalidCharReplacement() {
+    return xml10InvalidCharReplacement;
+  }  
+  
 
   private PrimitiveSerializerOptions() {}
 
@@ -123,6 +130,12 @@ public final class PrimitiveSerializerOptions {
       return this;
     }
 
+    /** set the replacement string for xml 1.0 unicode controlled characters that are not allowed */
+    public Builder xml10InvalidCharReplacement(final String replacement) {
+      options.xml10InvalidCharReplacement = replacement;
+      return this;
+    } 
+    
     /** Builds the OData serializer options. */
     public PrimitiveSerializerOptions build() {
       return options;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/PrimitiveValueSerializerOptions.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/PrimitiveValueSerializerOptions.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/PrimitiveValueSerializerOptions.java
index e84aaa4..c72f420 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/PrimitiveValueSerializerOptions.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/PrimitiveValueSerializerOptions.java
@@ -28,6 +28,7 @@ public class PrimitiveValueSerializerOptions {
   private Integer precision;
   private Integer scale;
   private Boolean isUnicode;
+  private String xml10InvalidCharReplacement;
 
   /** Gets the nullable facet. */
   public Boolean isNullable() {
@@ -53,6 +54,11 @@ public class PrimitiveValueSerializerOptions {
   public Boolean isUnicode() {
     return isUnicode;
   }
+  
+  /** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
+  public String xml10InvalidCharReplacement() {
+    return xml10InvalidCharReplacement;
+  }  
 
   private PrimitiveValueSerializerOptions() {}
 
@@ -109,7 +115,13 @@ public class PrimitiveValueSerializerOptions {
       options.isUnicode = property.isUnicode();
       return this;
     }
-
+    
+    /** set the replacement string for xml 1.0 unicode controlled characters that are not allowed */
+    public Builder xml10InvalidCharReplacement(final String replacement) {
+      options.xml10InvalidCharReplacement = replacement;
+      return this;
+    } 
+    
     /** Builds the OData serializer options. */
     public PrimitiveValueSerializerOptions build() {
       return options;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java
index 03a6675..b93ef4c 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java
@@ -97,57 +97,93 @@ import org.apache.olingo.server.api.edmx.EdmxReferenceIncludeAnnotation;
 public class MetadataParser {
   private boolean parseAnnotations = false;
   private static final String XML_LINK_NS = "http://www.w3.org/1999/xlink";
-  private ReferenceResolver defaultReferenceResolver = new DefaultReferenceResolver();
-  private boolean loadCoreVocabularies = false;
+  private ReferenceResolver referenceResolver = new DefaultReferenceResolver();
+  private boolean useLocalCoreVocabularies = true;
+  private boolean implicitlyLoadCoreVocabularies = false;
   
+  /**
+   * Avoid reading the annotations in the $metadata 
+   * @param parse
+   * @return
+   */
   public MetadataParser parseAnnotations(boolean parse) {
     this.parseAnnotations = parse;
     return this;
   }
-  
+
+  /**
+   * Externalize the reference loading, such that they can be loaded from local caches
+   * @param resolver
+   * @return
+   */
   public MetadataParser referenceResolver(ReferenceResolver resolver) {
-    this.defaultReferenceResolver = resolver;
+    this.referenceResolver = resolver;
     return this;
   }
   
-  public MetadataParser loadCoreVocabularies(boolean load) {
-    this.loadCoreVocabularies = load;
+  /**
+   * Load the core libraries from local classpath
+   * @param load true for yes; false otherwise
+   * @return
+   */
+  public MetadataParser useLocalCoreVocabularies(boolean load) {
+    this.useLocalCoreVocabularies = load;
+    return this;
+  }
+  
+  /**
+   * Load the core vocabularies, irrespective of if they are defined in the $metadata
+   * @param load
+   * @return
+   */
+  public MetadataParser implicitlyLoadCoreVocabularies(boolean load) {
+    this.implicitlyLoadCoreVocabularies = load;
     return this;
   }
   
   public ServiceMetadata buildServiceMetadata(Reader csdl) throws XMLStreamException {
-    SchemaBasedEdmProvider provider = buildEdmProvider(csdl,
-        this.defaultReferenceResolver, this.loadCoreVocabularies);
+    SchemaBasedEdmProvider provider = buildEdmProvider(csdl, this.referenceResolver,
+        this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies);
     return new ServiceMetadataImpl(provider, provider.getReferences(), null);
   }
 
   public SchemaBasedEdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
-    return buildEdmProvider(csdl, this.defaultReferenceResolver, this.loadCoreVocabularies);
+    XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
+    XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);    
+    return buildEdmProvider(reader, this.referenceResolver,
+        this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies);
   }
-    
+  
   protected SchemaBasedEdmProvider buildEdmProvider(Reader csdl,
-      ReferenceResolver referenceResolver, boolean loadCoreVocabularies) throws XMLStreamException {
+      ReferenceResolver resolver, boolean loadCore, boolean useLocal)
+      throws XMLStreamException {
     XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
-    XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
-    return buildEdmProvider(reader, referenceResolver, loadCoreVocabularies);
+    XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);    
+    return buildEdmProvider(reader, resolver, loadCore, useLocal);
   }
-  
+    
   protected SchemaBasedEdmProvider buildEdmProvider(InputStream csdl,
-      ReferenceResolver referenceResolver, boolean loadCoreVocabularies) throws XMLStreamException {
+      ReferenceResolver resolver, boolean loadCore, boolean useLocal)
+      throws XMLStreamException {
     XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
     XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
-    return buildEdmProvider(reader, referenceResolver, loadCoreVocabularies);
+    return buildEdmProvider(reader, resolver, loadCore, useLocal);
   } 
   
   protected SchemaBasedEdmProvider buildEdmProvider(XMLEventReader reader,
-      ReferenceResolver referenceResolver, boolean loadCoreVocabularies) throws XMLStreamException {
-    SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider(referenceResolver);
+      ReferenceResolver resolver, boolean loadCore, boolean useLocal)
+      throws XMLStreamException {
+    SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider();
+    
+    final StringBuilder xmlBase = new StringBuilder();
+    
     new ElementReader<SchemaBasedEdmProvider>() {
       @Override
       void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
           String name) throws XMLStreamException {
-        String xmlBase = attrNS(element, XML_LINK_NS, "base");
-        provider.setXMLBase(xmlBase);        
+        if (attrNS(element, XML_LINK_NS, "base") != null) {
+          xmlBase.append(attrNS(element, XML_LINK_NS, "base"));
+        }
         String version = attr(element, "Version");
         if ("4.0".equals(version)) {
           readDataServicesAndReference(reader, element, provider);
@@ -167,23 +203,100 @@ public class MetadataParser {
                   event.asEndElement().getName().getLocalPart()));
     }
     
-    // load the core vocabularies
-    if (loadCoreVocabularies) {
-      loadVocabularySchema(provider, "Org.OData.Core.V1", "Org.OData.Core.V1.xml");
-      loadVocabularySchema(provider, "Org.OData.Capabilities.V1", "Org.OData.Capabilities.V1.xml");
-      loadVocabularySchema(provider, "Org.OData.Measures.V1", "Org.OData.Measures.V1.xml");
-    }    
+    //load core vocabularies even though they are not defined in the references
+    if (loadCore) {
+      loadCoreVocabulary(provider, "Org.OData.Core.V1");
+      loadCoreVocabulary(provider, "Org.OData.Capabilities.V1");
+      loadCoreVocabulary(provider, "Org.OData.Measures.V1");
+    }
+    
+    // load all the reference schemas
+    if (resolver != null) {
+      loadReferencesSchemas(provider, xmlBase.length() == 0 ? null
+          : fixXmlBase(xmlBase.toString()), resolver, loadCore, useLocal);
+    }
     return provider;
   }  
   
-  private void loadVocabularySchema(SchemaBasedEdmProvider provider, String namespace,
+  private void loadReferencesSchemas(SchemaBasedEdmProvider provider,
+      String xmlBase, ReferenceResolver resolver, boolean loadCore,
+      boolean useLocal) {    
+
+    for (EdmxReference reference:provider.getReferences()) {
+      try {
+        SchemaBasedEdmProvider refProvider = null;
+
+        for (EdmxReferenceInclude include : reference.getIncludes()) {
+
+          // check if the schema is already loaded before.
+          if (provider.getSchema(include.getNamespace()) != null) {
+            continue;
+          }
+          
+          if (isCoreVocabulary(include.getNamespace()) && useLocal) {
+            loadCoreVocabulary(provider, include.getNamespace());
+            continue;
+          }
+                    
+          if (refProvider == null) {
+            InputStream is = this.referenceResolver.resolveReference(reference.getUri(), xmlBase);
+            if (is == null) {
+              throw new EdmException("Failed to load Reference "+reference.getUri()+" loading failed");
+            } else {
+              // do not implicitly load core vocabularies any more. But if the
+              // references loading the core vocabularies try to use local if we can 
+              refProvider = buildEdmProvider(is, resolver, false, useLocal);
+            }
+          }
+          
+          CsdlSchema refSchema = refProvider.getSchema(include.getNamespace(), false);
+          provider.addReferenceSchema(include.getNamespace(), refProvider);
+          if (include.getAlias() != null) {
+            refSchema.setAlias(include.getAlias());
+            provider.addReferenceSchema(include.getAlias(), refProvider);
+          }
+        }
+      } catch (XMLStreamException e) {
+        throw new EdmException("Failed to load Reference "+reference.getUri()+" parsing failed");
+      }
+    }
+  }
+  
+  private void loadCoreVocabulary(SchemaBasedEdmProvider provider,
+      String namespace) throws XMLStreamException {
+    if(namespace.equalsIgnoreCase("Org.OData.Core.V1")) {
+      loadLocalVocabularySchema(provider, "Org.OData.Core.V1", "Org.OData.Core.V1.xml");
+    } else if (namespace.equalsIgnoreCase("Org.OData.Capabilities.V1")) {
+      loadLocalVocabularySchema(provider, "Org.OData.Capabilities.V1", "Org.OData.Capabilities.V1.xml");
+    } else if (namespace.equalsIgnoreCase("Org.OData.Measures.V1")) {
+      loadLocalVocabularySchema(provider, "Org.OData.Measures.V1", "Org.OData.Measures.V1.xml");
+    }
+  }
+
+  private boolean isCoreVocabulary(String namespace) {
+    if(namespace.equalsIgnoreCase("Org.OData.Core.V1") || 
+        namespace.equalsIgnoreCase("Org.OData.Capabilities.V1") || 
+        namespace.equalsIgnoreCase("Org.OData.Measures.V1")) {
+      return true;
+    }
+    return false;
+  }
+
+  private String fixXmlBase(String base) {
+    if (base.endsWith("/")) {
+      return base;
+    } 
+    return base+"/";
+  }  
+  
+  private void loadLocalVocabularySchema(SchemaBasedEdmProvider provider, String namespace,
       String resource) throws XMLStreamException {
-    CsdlSchema schema = provider.getSchema(namespace, false);
+    CsdlSchema schema = provider.getVocabularySchema(namespace);
     if (schema == null) {
       InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource);
       if (is != null) {
-        SchemaBasedEdmProvider childProvider = buildEdmProvider(is, null, false);
-        provider.addSchema(childProvider.getSchema(namespace, false));
+        SchemaBasedEdmProvider childProvider = buildEdmProvider(is, null, false, false);
+        provider.addVocabularySchema(namespace, childProvider);
       } else {
         throw new XMLStreamException("failed to load "+resource+" core vocabulary");
       }
@@ -191,7 +304,8 @@ public class MetadataParser {
   }  
   
   private void readDataServicesAndReference(XMLEventReader reader,
-      StartElement element, SchemaBasedEdmProvider provider) throws XMLStreamException {
+      StartElement element, SchemaBasedEdmProvider provider)
+      throws XMLStreamException {
     final ArrayList<EdmxReference> references = new ArrayList<EdmxReference>();
     new ElementReader<SchemaBasedEdmProvider>() {
       @Override
@@ -384,7 +498,9 @@ public class MetadataParser {
     CsdlTypeDefinition td = new CsdlTypeDefinition();
     td.setName(attr(element, "Name"));
     td.setUnderlyingType(new FullQualifiedName(attr(element, "UnderlyingType")));
-    td.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
+    if (attr(element, "Unicode") != null) {
+      td.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
+    }
 
     String maxLength = attr(element, "MaxLength");
     if (maxLength != null) {
@@ -837,7 +953,9 @@ public class MetadataParser {
     property.setCollection(isCollectionType(element));
     property.setNullable(Boolean.parseBoolean(attr(element, "Nullable") == null ? "true" : attr(
         element, "Nullable")));
-    property.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
+    if (attr(element, "Unicode") != null) {
+      property.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
+    }
 
     String maxLength = attr(element, "MaxLength");
     if (maxLength != null) {
@@ -1077,18 +1195,23 @@ public class MetadataParser {
   private static class DefaultReferenceResolver implements ReferenceResolver {
     @Override
     public InputStream resolveReference(URI referenceUri, String xmlBase) {
-      URL schemaURL = null;
+      InputStream in = null;
       try {
         if (referenceUri.isAbsolute()) {
-          schemaURL = referenceUri.toURL();
+          URL schemaURL = referenceUri.toURL();
+          in = schemaURL.openStream();
         } else {
           if (xmlBase != null) {
-            schemaURL = new URL(xmlBase+referenceUri.toString());
+            URL schemaURL = new URL(xmlBase+referenceUri.toString());
+            in = schemaURL.openStream();
           } else {
-            throw new EdmException("No xml:base set to read the references from the metadata");
+            in = this.getClass().getClassLoader().getResourceAsStream(referenceUri.getPath());
+            if (in == null) {
+              throw new EdmException("No xml:base set to read the references from the metadata");
+            }
           }        
         }
-        return schemaURL.openStream();
+        return in;
       } catch (MalformedURLException e) {
         throw new EdmException(e);
       } catch (IOException e) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/SchemaBasedEdmProvider.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/SchemaBasedEdmProvider.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/SchemaBasedEdmProvider.java
index a778e2c..8aea555 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/SchemaBasedEdmProvider.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/SchemaBasedEdmProvider.java
@@ -18,15 +18,11 @@
  */
 package org.apache.olingo.server.core;
 
-import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
-import javax.xml.stream.XMLStreamException;
-
-import org.apache.olingo.commons.api.edm.EdmException;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.edm.provider.CsdlAction;
 import org.apache.olingo.commons.api.edm.provider.CsdlActionImport;
@@ -52,15 +48,11 @@ import org.apache.olingo.server.api.edmx.EdmxReferenceInclude;
 public class SchemaBasedEdmProvider implements CsdlEdmProvider {
   private final List<CsdlSchema> edmSchemas = new ArrayList<CsdlSchema>();
   private final Map<String, EdmxReference> references = new ConcurrentHashMap<String, EdmxReference>();
-  private final Map<String, SchemaBasedEdmProvider> referenceSchemas 
-    = new ConcurrentHashMap<String, SchemaBasedEdmProvider>();
-  private String xmlBase;
-  private ReferenceResolver referenceResolver;
+  private final Map<String, SchemaBasedEdmProvider> referenceSchemas = 
+      new ConcurrentHashMap<String, SchemaBasedEdmProvider>();
+  private final Map<String, SchemaBasedEdmProvider> coreVocabularySchemas = 
+      new ConcurrentHashMap<String, SchemaBasedEdmProvider>();
   
-  public SchemaBasedEdmProvider(ReferenceResolver referenceResolver) {
-    this.referenceResolver = referenceResolver;
-  }
-
   void addSchema(CsdlSchema schema) {
     this.edmSchemas.add(schema);
   }
@@ -68,7 +60,23 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
   List<EdmxReference> getReferences(){
     return new ArrayList<EdmxReference>(references.values());
   }
-
+  
+  void addReferenceSchema(String ns, SchemaBasedEdmProvider provider) {
+    this.referenceSchemas.put(ns, provider);
+  }  
+  
+  void addVocabularySchema(String ns, SchemaBasedEdmProvider provider) {
+    this.coreVocabularySchemas.put(ns, provider);
+  }
+  
+  CsdlSchema getVocabularySchema(String ns) {
+    SchemaBasedEdmProvider provider = this.coreVocabularySchemas.get(ns);
+    if (provider != null) {
+      return provider.getSchema(ns, false);
+    }
+    return null;
+  }
+  
   CsdlSchema getSchema(String ns) {
     return getSchema(ns, true);
   }  
@@ -79,46 +87,20 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
         return s;
       }
     }
+    CsdlSchema s = null; 
     if (checkReferences) {
-      return getReferenceSchema(ns);
+      s = getReferenceSchema(ns);
+      if (s == null) {
+        s = getVocabularySchema(ns);
+      }
     }
-    return null;
+    return s;
   }
 
-  private CsdlSchema getReferenceSchema(String ns) {
+  CsdlSchema getReferenceSchema(String ns) {
     if (ns == null) {
       return null;
     }
-    if (this.referenceSchemas.get(ns) == null) {
-      EdmxReference reference = this.references.get(ns);
-      if (reference != null) {
-        SchemaBasedEdmProvider provider = null;
-        if (this.referenceResolver == null) {
-          throw new EdmException("Failed to load Reference "+reference.getUri());
-        } else {
-          InputStream is = this.referenceResolver.resolveReference(reference.getUri(), this.xmlBase);
-          if (is != null) {
-            try {
-              MetadataParser parser = new MetadataParser();
-              provider = parser.buildEdmProvider(is, this.referenceResolver, false);
-            } catch (XMLStreamException e) {
-              throw new EdmException("Failed to load Reference "+reference.getUri()+" parsing failed");
-            }
-          } else {
-            throw new EdmException("Failed to load Reference "+reference.getUri()+" loading failed");
-          }
-        }
-        // copy references
-        for (EdmxReferenceInclude include : reference.getIncludes()) {
-          this.referenceSchemas.put(include.getNamespace(), provider);
-          if (include.getAlias() != null) {
-            CsdlSchema schema = provider.getSchema(include.getNamespace());
-            schema.setAlias(include.getAlias());
-            this.referenceSchemas.put(include.getAlias(), provider);
-          }
-        }
-      }
-    }
     
     if (this.referenceSchemas.get(ns) != null) {
       return this.referenceSchemas.get(ns).getSchema(ns);  
@@ -133,7 +115,7 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
     }
     return null;
   }
-
+  
   @Override
   public CsdlEnumType getEnumType(FullQualifiedName fqn) throws ODataException {
     CsdlSchema schema = getSchema(fqn.getNamespace());
@@ -402,15 +384,5 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
         }
       }
     }
-  }
-
-  public void setXMLBase(String base) {
-    if (base != null) {
-      if (base.endsWith("/")) {
-        this.xmlBase = base;
-      } else {
-        this.xmlBase = base+"/";
-      }
-    }
   } 
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
index 0796144..f6b3296 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
@@ -27,14 +27,18 @@ import java.util.Map;
 import java.util.StringTokenizer;
 
 import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.edm.EdmAnnotation;
+import org.apache.olingo.commons.api.edm.EdmSchema;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.annotation.EdmConstantExpression;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataLibraryException;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
-import org.apache.olingo.server.api.ODataLibraryException;
 import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
 import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
@@ -140,26 +144,60 @@ public abstract class ServiceRequest {
     return this.request.getMethod() == HttpMethod.POST;
   }
 
+  private static FullQualifiedName XML10_CHAR_REPLACE_FQN = new FullQualifiedName(
+      "org.apache.olingo.v1.xml10-incompatible-char-replacement");
+  /**
+   * Replacement character for the XML10 characters that are not supported.
+   * @return
+   */
+  protected String xml10IncompatibleCharReplacement() {
+    for (EdmSchema schema : getServiceMetaData().getEdm().getSchemas()) {
+      if (schema.getEntityContainer() != null) {
+        for (EdmAnnotation annotation:schema.getAnnotations()) {
+          if (annotation.getTerm() != null
+              && annotation.getTerm().getFullQualifiedName().equals(XML10_CHAR_REPLACE_FQN)) {
+            EdmConstantExpression expr = annotation.getExpression().asConstant();
+            return expr.getValueAsString();            
+          }
+        }
+      }
+    }
+    return null;
+  }
+  
   @SuppressWarnings("unchecked")
-  public <T> T getSerializerOptions(Class<T> serilizerOptions, ContextURL contextUrl,
-      boolean references) throws ContentNegotiatorException {
+  public <T> T getSerializerOptions(Class<T> serilizerOptions,
+      ContextURL contextUrl, boolean references) throws ContentNegotiatorException {
+    
+    String xmlReplacement = null;
+    if (getResponseContentType().isCompatible(ContentType.APPLICATION_XML)
+        || getResponseContentType().isCompatible(ContentType.APPLICATION_ATOM_XML)) {
+      xmlReplacement = xml10IncompatibleCharReplacement();
+    }
     
     if (serilizerOptions.isAssignableFrom(EntitySerializerOptions.class)) {
       return (T) EntitySerializerOptions.with()
           .contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl)
           .expand(uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption())
-          .writeOnlyReferences(references).build();
+          .writeOnlyReferences(references)
+          .xml10InvalidCharReplacement(xmlReplacement)
+          .build();
     } else if (serilizerOptions.isAssignableFrom(EntityCollectionSerializerOptions.class)) {
       return (T) EntityCollectionSerializerOptions.with()
           .contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl)
           .count(uriInfo.getCountOption()).expand(uriInfo.getExpandOption())
           .select(uriInfo.getSelectOption()).writeOnlyReferences(references)
-          .id(getODataRequest().getRawBaseUri() + getODataRequest().getRawODataPath()).build();
+          .id(getODataRequest().getRawBaseUri() + getODataRequest().getRawODataPath())
+          .xml10InvalidCharReplacement(xmlReplacement)
+          .build();
     } else if (serilizerOptions.isAssignableFrom(ComplexSerializerOptions.class)) {
       return (T) ComplexSerializerOptions.with().contextURL(contextUrl)
-          .expand(this.uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption()).build();
+          .expand(this.uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption())
+          .xml10InvalidCharReplacement(xmlReplacement)
+          .build();
     } else if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) {
       return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl)
+          .xml10InvalidCharReplacement(xmlReplacement)
           .build();
     }
     return null;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
index 42fbdea..45e1ed6 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
@@ -248,10 +248,19 @@ public class DataRequest extends ServiceRequest {
   @SuppressWarnings("unchecked")
   @Override
   public <T> T getSerializerOptions(Class<T> serilizerOptions, ContextURL contextUrl, boolean references)
-      throws ContentNegotiatorException {
+      throws ContentNegotiatorException {   
     if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) {
+      
+      String xmlReplacement = null;
+      if (getResponseContentType().isCompatible(ContentType.APPLICATION_XML)
+          || getResponseContentType().isCompatible(ContentType.APPLICATION_ATOM_XML)) {
+        xmlReplacement = xml10IncompatibleCharReplacement();
+      }      
+      
       return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl)
-          .facetsFrom(getUriResourceProperty().getProperty()).build();
+          .facetsFrom(getUriResourceProperty().getProperty())
+          .xml10InvalidCharReplacement(xmlReplacement)
+          .build();
     }
     return super.getSerializerOptions(serilizerOptions, contextUrl, references);
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/main/resources/org.apache.olingo.v1.xml
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/resources/org.apache.olingo.v1.xml b/lib/server-core-ext/src/main/resources/org.apache.olingo.v1.xml
new file mode 100644
index 0000000..d197e45
--- /dev/null
+++ b/lib/server-core-ext/src/main/resources/org.apache.olingo.v1.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  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.
+
+-->
+
+<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
+  <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/os/vocabularies/Org.OData.Core.V1.xml">
+    <edmx:Include Alias="Core" Namespace="Org.OData.Core.V1" />
+  </edmx:Reference>
+  <edmx:DataServices>
+    <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="org.apache.olingo.v1" Alias="olingo-extensions">
+
+      <Term Name="xml10-incompatible-char-replacement" Type="Edm.String" AppliesTo="PropertyValue ReturnType">
+        <Annotation Term="Core.Description">
+          <String>
+            Replacement character for invalid characters in the XML 1.0 Atom payload
+          </String>
+        </Annotation>
+      </Term>
+      
+    </Schema>
+  </edmx:DataServices>
+</edmx:Edmx>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserAnnotationsTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserAnnotationsTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserAnnotationsTest.java
index d71c54d..75c12ad 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserAnnotationsTest.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserAnnotationsTest.java
@@ -60,7 +60,7 @@ public class MetadataParserAnnotationsTest {
   public void setUp() throws Exception {
     MetadataParser parser = new MetadataParser();
     parser.parseAnnotations(true);
-    parser.loadCoreVocabularies(true);
+    parser.useLocalCoreVocabularies(true);
     provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/annotations.xml"));
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserTest.java
index 83160b4..8afe5d2 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserTest.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserTest.java
@@ -54,7 +54,6 @@ public class MetadataParserTest {
   @Before
   public void setUp() throws Exception {
     MetadataParser parser = new MetadataParser();
-    parser.parseAnnotations(true);
     provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/trippin.xml"));
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/ServiceDispatcherTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/ServiceDispatcherTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/ServiceDispatcherTest.java
index 90ead94..ab4a62a 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/ServiceDispatcherTest.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/ServiceDispatcherTest.java
@@ -91,6 +91,9 @@ public class ServiceDispatcherTest {
   
   public void beforeTest(ServiceHandler serviceHandler) throws Exception {
     MetadataParser parser = new MetadataParser();
+    parser.parseAnnotations(true);
+    parser.useLocalCoreVocabularies(true);
+    parser.implicitlyLoadCoreVocabularies(true);
     ServiceMetadata metadata = parser.buildServiceMetadata(new FileReader("src/test/resources/trippin.xml"));
 
     File baseDir = new File(System.getProperty("java.io.tmpdir"));

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
index 3beb274..ec0c7c7 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
@@ -114,20 +114,23 @@ public class TripPinServiceTest {
   }
 
   @Test
-  public void testEntitySet() throws Exception {
-    HttpRequest req = new HttpGet(baseURL+"/People");
-    req.setHeader("Content-Type", "application/json;odata.metadata=minimal");
+  public void testXMLInvalidChars() throws Exception {
+    HttpRequest req = new HttpGet(baseURL+"/Airlines('FM')");
+    req.setHeader("Accept", "application/xml");
 
     HttpResponse response = httpSend(req, 200);
-    JsonNode node = getJSONNode(response);
-
-    assertEquals("$metadata#People", node.get("@odata.context").asText());
-    assertEquals(baseURL+"/People?$skiptoken=8", node.get("@odata.nextLink").asText());
-
-    JsonNode person = ((ArrayNode)node.get("value")).get(0);
-    assertEquals("russellwhyte", person.get("UserName").asText());
+    String actual = IOUtils.toString(response.getEntity().getContent());
+    String expected = 
+        "<m:properties>"
+        +     "<d:AirlineCode>FM</d:AirlineCode>"
+        +     "<d:Name>Shanghai xxxAirlinexxx</d:Name>" 
+        +     "<d:Picture m:null=\"true\"/>" 
+        +  "</m:properties>"  
+        + "</a:content>"  
+        +"</a:entry>";
+    assertTrue(actual.endsWith(expected));
   }
-
+  
   @Test
   public void testReadEntitySetWithPaging() throws Exception {
     String url = baseURL+"/People";

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServlet.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServlet.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServlet.java
index 06e498c..7ab019d 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServlet.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServlet.java
@@ -51,7 +51,8 @@ public class TripPinServlet extends HttpServlet {
 
     try {
       parser.parseAnnotations(true);
-      parser.loadCoreVocabularies(true);
+      parser.useLocalCoreVocabularies(true);
+      parser.implicitlyLoadCoreVocabularies(true);
       metadata = parser.buildServiceMetadata(new FileReader("src/test/resources/trippin.xml"));
     } catch (XMLStreamException e) {
       throw new IOException(e);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/test/resources/airlines.json
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/resources/airlines.json b/lib/server-core-ext/src/test/resources/airlines.json
index 1d93aa7..9019c97 100644
--- a/lib/server-core-ext/src/test/resources/airlines.json
+++ b/lib/server-core-ext/src/test/resources/airlines.json
@@ -10,7 +10,7 @@
       },
       {
          "AirlineCode":"FM",
-         "Name":"Shanghai Airline"
+         "Name":"Shanghai \u0000Airline\u0001"
       },
       {
          "AirlineCode":"MU",

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/test/resources/annotations.xml
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/resources/annotations.xml b/lib/server-core-ext/src/test/resources/annotations.xml
index 1c5281a..3c8570f 100644
--- a/lib/server-core-ext/src/test/resources/annotations.xml
+++ b/lib/server-core-ext/src/test/resources/annotations.xml
@@ -11,6 +11,9 @@
   language governing permissions and limitations under the License. -->
 <edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
 	Version="4.0">
+  <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/os/vocabularies/Org.OData.Core.V1.xml">
+    <edmx:Include Alias="Core" Namespace="Org.OData.Core.V1" />
+  </edmx:Reference>	
 	<edmx:DataServices>
 		<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm"
 			Namespace="Org.OData.AnnoatationTest" Alias="test">

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core-ext/src/test/resources/trippin.xml
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/resources/trippin.xml b/lib/server-core-ext/src/test/resources/trippin.xml
index 3266344..5970ea2 100644
--- a/lib/server-core-ext/src/test/resources/trippin.xml
+++ b/lib/server-core-ext/src/test/resources/trippin.xml
@@ -10,6 +10,9 @@
 	OF ANY KIND, either express or implied. See the License for the specific 
 	language governing permissions and limitations under the License. -->
 <edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
+  <edmx:Reference Uri="org.apache.olingo.v1.xml">
+    <edmx:Include Alias="olingo-extensions" Namespace="org.apache.olingo.v1" />
+  </edmx:Reference>
 	<edmx:DataServices>
 		<Schema Namespace="Microsoft.OData.SampleService.Models.TripPin"
 			xmlns="http://docs.oasis-open.org/odata/ns/edm">
@@ -103,7 +106,7 @@
 						<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
 					</Annotation>
 				</Property>
-				<Property Name="Name" Type="Edm.String" Nullable="false" />
+				<Property Name="Name" Type="Edm.String" Nullable="false"/>
 				<Property Name="IataCode" Type="Edm.String" Nullable="false">
 					<Annotation Term="Org.OData.Core.V1.Immutable" Bool="true" />
 				</Property>
@@ -453,6 +456,7 @@
 				</Annotation>
 				<Annotation Term="Core.RequiresType" String="Edm.String" />
 			</Term>
+		 <Annotation Term="org.apache.olingo.v1.xml10-incompatible-char-replacement" String="xxx"/>
 		</Schema>
 	</edmx:DataServices>
 </edmx:Edmx>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
index 0057db4..a72e096 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
@@ -52,6 +52,7 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
 import org.apache.olingo.commons.api.ex.ODataErrorDetail;
 import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
@@ -250,10 +251,10 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
       }
 
       if (options == null) {
-        writeEntitySet(metadata, entityType, entitySet, null, null, writer);
+        writeEntitySet(metadata, entityType, entitySet, null, null, null, writer);
       } else {
         writeEntitySet(metadata, entityType, entitySet,
-            options.getExpand(), options.getSelect(), writer);
+            options.getExpand(), options.getSelect(), options.xml10InvalidCharReplacement(), writer);
       }
 
       writer.writeEndElement();
@@ -296,7 +297,9 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
       writer.writeStartDocument(DEFAULT_CHARSET, "1.0");
       writeEntity(metadata, entityType, entity, contextURL,
           options == null ? null : options.getExpand(),
-          options == null ? null : options.getSelect(), writer, true);
+          options == null ? null : options.getSelect(),
+          options == null ? null : options.xml10InvalidCharReplacement(),
+          writer, true);
       writer.writeEndDocument();
 
       writer.flush();
@@ -336,15 +339,17 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
 
   protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
       final EntityCollection entitySet, final ExpandOption expand, final SelectOption select,
-      final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
+      final String xml10InvalidCharReplacement,final XMLStreamWriter writer) 
+          throws XMLStreamException, SerializerException {
     for (final Entity entity : entitySet.getEntities()) {
-      writeEntity(metadata, entityType, entity, null, expand, select, writer, false);
+      writeEntity(metadata, entityType, entity, null, expand, select, xml10InvalidCharReplacement, writer, false);
     }
   }
 
   protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
       final Entity entity, final ContextURL contextURL, final ExpandOption expand,
-      final SelectOption select, final XMLStreamWriter writer, final boolean top)
+      final SelectOption select, final String xml10InvalidCharReplacement,
+      final XMLStreamWriter writer, final boolean top)
       throws XMLStreamException, SerializerException {
 
     writer.writeStartElement(ATOM, Constants.ATOM_ELEM_ENTRY, NS_ATOM);
@@ -397,7 +402,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
     }
 
     EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType());
-    writeNavigationProperties(metadata, resolvedType, entity, expand, writer);
+    writeNavigationProperties(metadata, resolvedType, entity, expand, xml10InvalidCharReplacement, writer);
 
     writer.writeStartElement(ATOM, Constants.ATOM_ELEM_CATEGORY, NS_ATOM);
     writer.writeAttribute(Constants.ATOM_ATTR_SCHEME, Constants.NS_SCHEME);
@@ -412,7 +417,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
     }
 
     writer.writeStartElement(METADATA, Constants.PROPERTIES, NS_METADATA);
-    writeProperties(metadata, resolvedType, entity.getProperties(), select, writer);
+    writeProperties(metadata, resolvedType, entity.getProperties(), select, xml10InvalidCharReplacement, writer);
     writer.writeEndElement(); // properties
 
     if (!entityType.hasStream()) { // content
@@ -490,8 +495,8 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
   }
 
   protected void writeProperties(final ServiceMetadata metadata, final EdmStructuredType type,
-      final List<Property> properties, final SelectOption select, final XMLStreamWriter writer)
-      throws XMLStreamException, SerializerException {
+      final List<Property> properties, final SelectOption select, final String xml10InvalidCharReplacement, 
+      final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
     final boolean all = ExpandSelectHelper.isAll(select);
     final Set<String> selected = all ? new HashSet<String>() :
         ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems());
@@ -501,14 +506,15 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
         final Property property = findProperty(propertyName, properties);
         final Set<List<String>> selectedPaths = all || edmProperty.isPrimitive() ? null :
             ExpandSelectHelper.getSelectedPaths(select.getSelectItems(), propertyName);
-        writeProperty(metadata, edmProperty, property, selectedPaths, writer);
+        writeProperty(metadata, edmProperty, property, selectedPaths, xml10InvalidCharReplacement, writer);
       }
     }
   }
 
   protected void writeNavigationProperties(final ServiceMetadata metadata,
       final EdmStructuredType type, final Linked linked, final ExpandOption expand,
-      final XMLStreamWriter writer) throws SerializerException, XMLStreamException {
+      final String xml10InvalidCharReplacement, final XMLStreamWriter writer) 
+          throws SerializerException, XMLStreamException {
     if (ExpandSelectHelper.hasExpand(expand)) {
       final boolean expandAll = ExpandSelectHelper.isExpandAll(expand);
       final Set<String> expanded = expandAll ? new HashSet<String>() :
@@ -529,7 +535,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
             writeExpandedNavigationProperty(metadata, property, navigationLink,
                 innerOptions == null ? null : innerOptions.getExpandOption(),
                 innerOptions == null ? null : innerOptions.getSelectOption(),
-                writer);
+                    xml10InvalidCharReplacement, writer);
             writer.writeEndElement();
             writer.writeEndElement();
           }
@@ -588,27 +594,28 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
 
   protected void writeExpandedNavigationProperty(final ServiceMetadata metadata,
       final EdmNavigationProperty property, final Link navigationLink,
-      final ExpandOption innerExpand, final SelectOption innerSelect, final XMLStreamWriter writer)
-      throws XMLStreamException, SerializerException {
+      final ExpandOption innerExpand, final SelectOption innerSelect, final String xml10InvalidCharReplacement,
+      final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
     if (property.isCollection()) {
       if (navigationLink != null && navigationLink.getInlineEntitySet() != null) {
         writer.writeStartElement(ATOM, Constants.ATOM_ELEM_FEED, NS_ATOM);
         writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
-            innerSelect, writer);
+            innerSelect, xml10InvalidCharReplacement, writer);
         writer.writeEndElement();
       }
     } else {
       if (navigationLink != null && navigationLink.getInlineEntity() != null) {
         writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null,
-            innerExpand, innerSelect, writer, false);
+            innerExpand, innerSelect, xml10InvalidCharReplacement, writer, false);
       }
     }
   }
 
-  protected void writeProperty(final ServiceMetadata metadata, final EdmProperty edmProperty,
-      final Property property,
-      final Set<List<String>> selectedPaths, final XMLStreamWriter writer) throws XMLStreamException,
-      SerializerException {
+  protected void writeProperty(final ServiceMetadata metadata,
+      final EdmProperty edmProperty, final Property property,
+      final Set<List<String>> selectedPaths,
+      final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
+      throws XMLStreamException, SerializerException {
     writer.writeStartElement(DATA, edmProperty.getName(), NS_DATA);
     if (property == null || property.isNull()) {
       if (edmProperty.isNullable()) {
@@ -618,7 +625,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
             SerializerException.MessageKeys.MISSING_PROPERTY, edmProperty.getName());
       }
     } else {
-      writePropertyValue(metadata, edmProperty, property, selectedPaths, writer);
+      writePropertyValue(metadata, edmProperty, property, selectedPaths, xml10InvalidCharReplacement, writer);
     }
     writer.writeEndElement();
   }
@@ -642,9 +649,11 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
     return definedType;
   }
 
-  private void writePropertyValue(final ServiceMetadata metadata, final EdmProperty edmProperty,
-      final Property property, final Set<List<String>> selectedPaths,
-      final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
+  private void writePropertyValue(final ServiceMetadata metadata,
+      final EdmProperty edmProperty, final Property property,
+      final Set<List<String>> selectedPaths,
+      final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
+      throws XMLStreamException, SerializerException {
     try {
       if (edmProperty.isPrimitive()
           || edmProperty.getType().getKind() == EdmTypeKind.ENUM
@@ -657,22 +666,23 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
           writePrimitiveCollection((EdmPrimitiveType) edmProperty.getType(), property,
               edmProperty.isNullable(), edmProperty.getMaxLength(),
               edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
-              writer);
+              xml10InvalidCharReplacement,writer);
         } else {
           writePrimitive((EdmPrimitiveType) edmProperty.getType(), property,
               edmProperty.isNullable(), edmProperty.getMaxLength(),
               edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
-              writer);
+              xml10InvalidCharReplacement, writer);
         }
       } else if (property.isComplex()) {
         if (edmProperty.isCollection()) {
           writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE, collectionType(edmProperty.getType()));
-          writeComplexCollection(metadata, (EdmComplexType) edmProperty.getType(), property, selectedPaths, writer);
+          writeComplexCollection(metadata, (EdmComplexType) edmProperty.getType(), property, selectedPaths, 
+              xml10InvalidCharReplacement, writer);
         } else {
           writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE,
               "#" + complexType(metadata, (EdmComplexType) edmProperty.getType(), property.getType()));
           writeComplexValue(metadata, property, (EdmComplexType) edmProperty.getType(), property.asComplex().getValue(),
-              selectedPaths, writer);
+              selectedPaths, xml10InvalidCharReplacement, writer);
         }
       } else {
         throw new SerializerException("Property type not yet supported!",
@@ -687,14 +697,15 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
 
   private void writePrimitiveCollection(final EdmPrimitiveType type, final Property property,
       final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
-      final Boolean isUnicode,
+      final Boolean isUnicode, final String xml10InvalidCharReplacement,
       final XMLStreamWriter writer) throws XMLStreamException, EdmPrimitiveTypeException, SerializerException {
     for (Object value : property.asCollection()) {
       writer.writeStartElement(METADATA, Constants.ELEM_ELEMENT, NS_METADATA);
       switch (property.getValueType()) {
       case COLLECTION_PRIMITIVE:
       case COLLECTION_ENUM:
-        writePrimitiveValue(type, value, isNullable, maxLength, precision, scale, isUnicode, writer);
+        writePrimitiveValue(type, value, isNullable, maxLength, precision,
+            scale, isUnicode, xml10InvalidCharReplacement, writer);
         break;
       case COLLECTION_GEOSPATIAL:
         throw new SerializerException("Property type not yet supported!",
@@ -707,8 +718,9 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
     }
   }
 
-  private void writeComplexCollection(final ServiceMetadata metadata, final EdmComplexType type,
-      final Property property, final Set<List<String>> selectedPaths, final XMLStreamWriter writer)
+  private void writeComplexCollection(final ServiceMetadata metadata,
+      final EdmComplexType type, final Property property, final Set<List<String>> selectedPaths,
+      final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
       throws XMLStreamException, SerializerException {
     for (Object value : property.asCollection()) {
       writer.writeStartElement(METADATA, Constants.ELEM_ELEMENT, NS_METADATA);
@@ -717,7 +729,9 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
       }
       switch (property.getValueType()) {
       case COLLECTION_COMPLEX:
-        writeComplexValue(metadata, property, type, ((ComplexValue) value).getValue(), selectedPaths, writer);
+        writeComplexValue(metadata, property, type,
+            ((ComplexValue) value).getValue(), selectedPaths,
+            xml10InvalidCharReplacement, writer);
         break;
       default:
         throw new SerializerException("Property type not yet supported!",
@@ -729,7 +743,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
 
   private void writePrimitive(final EdmPrimitiveType type, final Property property,
       final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
-      final Boolean isUnicode, final XMLStreamWriter writer)
+      final Boolean isUnicode, final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
       throws EdmPrimitiveTypeException, XMLStreamException, SerializerException {
     if (property.isPrimitive()) {
       if (type != EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String)) {
@@ -739,7 +753,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
                 type.getName());
       }
       writePrimitiveValue(type, property.asPrimitive(),
-          isNullable, maxLength, precision, scale, isUnicode, writer);
+          isNullable, maxLength, precision, scale, isUnicode, xml10InvalidCharReplacement, writer);
     } else if (property.isGeospatial()) {
       throw new SerializerException("Property type not yet supported!",
           SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
@@ -747,7 +761,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
       writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE,
           "#" + type.getFullQualifiedName().getFullQualifiedNameAsString());
       writePrimitiveValue(type, property.asEnum(),
-          isNullable, maxLength, precision, scale, isUnicode, writer);
+          isNullable, maxLength, precision, scale, isUnicode, xml10InvalidCharReplacement, writer);
     } else {
       throw new SerializerException("Inconsistent property type!",
           SerializerException.MessageKeys.INCONSISTENT_PROPERTY_TYPE, property.getName());
@@ -756,19 +770,23 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
 
   protected void writePrimitiveValue(final EdmPrimitiveType type, final Object primitiveValue,
       final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
-      final Boolean isUnicode,
+      final Boolean isUnicode, final String xml10InvalidCharReplacement,
       final XMLStreamWriter writer) throws EdmPrimitiveTypeException, XMLStreamException {
     final String value = type.valueToString(primitiveValue,
         isNullable, maxLength, precision, scale, isUnicode);
     if (value == null) {
       writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_NULL, "true");
     } else {
-      writer.writeCharacters(value);
+      // XML 1.0 does not handle certain unicode characters, they need to be replaced
+      writer.writeCharacters(replaceInvalidCharacters(type, value,
+          isUnicode, xml10InvalidCharReplacement));
     }
   }
 
-  protected void writeComplexValue(final ServiceMetadata metadata, Property complexProperty, final EdmComplexType type,
-      final List<Property> properties, final Set<List<String>> selectedPaths, final XMLStreamWriter writer)
+  protected void writeComplexValue(final ServiceMetadata metadata,
+      Property complexProperty, final EdmComplexType type,
+      final List<Property> properties, final Set<List<String>> selectedPaths,
+      final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
       throws XMLStreamException, SerializerException {
 
     final EdmComplexType resolvedType = resolveComplexType(metadata,
@@ -779,7 +797,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
       if (selectedPaths == null || ExpandSelectHelper.isSelected(selectedPaths, propertyName)) {
         writeProperty(metadata, (EdmProperty) resolvedType.getProperty(propertyName), property,
             selectedPaths == null ? null : ExpandSelectHelper.getReducedSelectedPaths(selectedPaths, propertyName),
-            writer);
+            xml10InvalidCharReplacement, writer);
       }
     }
   }
@@ -822,6 +840,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
             options == null ? null : options.getPrecision(),
             options == null ? null : options.getScale(),
             options == null ? null : options.isUnicode(),
+            options == null ? null : options.xml10InvalidCharReplacement(),
             writer);
       }
       writer.writeEndElement();
@@ -874,7 +893,10 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
         writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_NULL, "true");
       } else {
         final List<Property> values = property.asComplex().getValue();
-        writeProperties(metadata, resolvedType, values, options == null ? null : options.getSelect(), writer);
+        writeProperties(metadata, resolvedType, values, 
+            options == null ? null : options.getSelect(),
+            options == null ? null : options.xml10InvalidCharReplacement(),
+            writer);
       }
       writer.writeEndDocument();
       writer.flush();
@@ -922,6 +944,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
           options == null ? null : options.getPrecision(),
           options == null ? null : options.getScale(),
           options == null ? null : options.isUnicode(),
+          options == null ? null : options.xml10InvalidCharReplacement(),
           writer);
       writer.writeEndElement();
       writer.writeEndDocument();
@@ -967,7 +990,8 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
       writer.writeAttribute(METADATA, NS_METADATA, Constants.CONTEXT,
           ContextURLBuilder.create(contextURL).toASCIIString());
       writeMetadataETag(metadata, writer);
-      writeComplexCollection(metadata, type, property, null, writer);
+      writeComplexCollection(metadata, type, property, null, 
+          options == null ? null:options.xml10InvalidCharReplacement(), writer);
       writer.writeEndElement();
       writer.writeEndDocument();
       writer.flush();
@@ -1104,4 +1128,30 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
     writer.writeAttribute(Constants.ATTR_HREF, entitySet.getNext().toASCIIString());
     writer.writeEndElement();
   }
+  
+  static String replaceInvalidCharacters(EdmPrimitiveType expectedType,
+      String value, Boolean isUniCode, String invalidCharacterReplacement) {
+    if (!(expectedType instanceof EdmString)
+        || invalidCharacterReplacement == null || isUniCode == null || !isUniCode) {
+      return value;
+    }
+    String s = (String) value;
+    StringBuilder result = null;
+    for (int i = 0; i < s.length(); i++) {
+      char c = s.charAt(i);
+      if (c <= 0x0020 && c != ' ' && c != '\n' && c != '\t' && c != '\r') {
+        if (result == null) {
+          result = new StringBuilder();
+          result.append(s.substring(0, i));
+        }
+        result.append(invalidCharacterReplacement);
+      } else if (result != null) {
+        result.append(c);
+      }
+    }
+    if (result == null) {
+      return value;
+    }
+    return result.toString();
+  }  
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d880d6c4/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java
index c904ea7..07b5e56 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java
@@ -1796,6 +1796,30 @@ public class ODataXmlSerializerTest {
   }
 
   @Test
+  public void testXML10ReplacementChar() throws Exception {
+    final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
+    final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyString");
+    final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
+    property.setValue(ValueType.PRIMITIVE, "ab\u0000cd\u0001");
+    final String resultString = IOUtils.toString(serializer
+        .primitive(metadata, (EdmPrimitiveType) edmProperty.getType(), property,
+            PrimitiveSerializerOptions.with()
+                .contextURL(ContextURL.with()
+                    .entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName())
+                    .build())
+                .xml10InvalidCharReplacement("XX")
+                .unicode(Boolean.TRUE)
+                .build()).getContent());
+
+    String expected = "<?xml version='1.0' encoding='UTF-8'?>"
+        + "<m:value xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\" "
+        + "m:context=\"$metadata#ESAllPrim(32767)/PropertyString\" "
+        + "m:metadata-etag=\"metadataETag\">"
+        + "abXXcdXX</m:value>";
+    Assert.assertEquals(expected, resultString);
+  }
+  
+  @Test
   public void primitivePropertyNull() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
     final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyString");
@@ -1966,8 +1990,7 @@ public class ODataXmlSerializerTest {
     XMLAssert.assertXMLEqual(diff, true);
   }
   
-  private static class CustomDifferenceListener implements DifferenceListener {
-
+  public static class CustomDifferenceListener implements DifferenceListener {
     @Override
     public int differenceFound(Difference difference) {
       final String xpath = "/updated[1]/text()[1]";