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 2014/09/23 15:01:34 UTC

[3/6] git commit: [OLINGO-422] Added ODataSerializerOptions

[OLINGO-422] Added ODataSerializerOptions


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

Branch: refs/heads/master
Commit: 461cdbbe23fbf0048fbdbfe2994858bc44a89d08
Parents: b41129c
Author: Michael Bolz <mi...@sap.com>
Authored: Fri Sep 12 09:52:32 2014 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Fri Sep 12 09:52:32 2014 +0200

----------------------------------------------------------------------
 .../olingo/commons/api/data/ContextURL.java     |  11 +-
 .../core/serialization/ContextURLParser.java    |  35 +++--
 .../server/api/serializer/ODataSerializer.java  |   6 +-
 .../api/serializer/ODataSerializerOptions.java  |  87 +++++++++++
 .../core/serializer/ODataXmlSerializerImpl.java |   9 +-
 .../serializer/json/ODataJsonSerializer.java    |  76 ++++++----
 .../serializer/utils/ExpandSelectHelper.java    |  19 ++-
 .../serializer/utils/ContextURLBuilderTest.java |  20 +--
 .../tecsvc/processor/TechnicalProcessor.java    |  20 ++-
 .../json/ODataJsonSerializerTest.java           | 146 ++++++++++++-------
 10 files changed, 283 insertions(+), 146 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/461cdbbe/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
index 1e6f182..7b750de 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
@@ -110,17 +110,14 @@ public class ContextURL {
     return suffix == Suffix.DELTA_DELETED_LINK;
   }
 
+  public static Builder with() {
+    return new Builder();
+  }
+
   public static final class Builder {
 
     private ContextURL contextURL = new ContextURL();
 
-    private Builder() {
-    }
-
-    public static final Builder create() {
-      return new Builder();
-    }
-
     public Builder serviceRoot(final URI serviceRoot) {
       contextURL.serviceRoot = serviceRoot;
       return this;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/461cdbbe/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/ContextURLParser.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/ContextURLParser.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/ContextURLParser.java
index c7f5ca5..1190a84 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/ContextURLParser.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/ContextURLParser.java
@@ -34,39 +34,39 @@ public class ContextURLParser {
       return null;
     }
 
-    final ContextURL.Builder builder = ContextURL.Builder.create();
+    final ContextURL.Builder contextUrl = ContextURL.with();
 
     String contextURLasString = contextURL.toASCIIString();
 
     boolean isEntity = false;
     if (contextURLasString.endsWith("/$entity") || contextURLasString.endsWith("/@Element")) {
       isEntity = true;
-      builder.suffix(Suffix.ENTITY);
+      contextUrl.suffix(Suffix.ENTITY);
       contextURLasString = contextURLasString.replace("/$entity", StringUtils.EMPTY).
               replace("/@Element", StringUtils.EMPTY);
     } else if (contextURLasString.endsWith("/$ref")) {
-      builder.suffix(Suffix.REFERENCE);
+      contextUrl.suffix(Suffix.REFERENCE);
       contextURLasString = contextURLasString.replace("/$ref", StringUtils.EMPTY);
     } else if (contextURLasString.endsWith("/$delta")) {
-      builder.suffix(Suffix.DELTA);
+      contextUrl.suffix(Suffix.DELTA);
       contextURLasString = contextURLasString.replace("/$delta", StringUtils.EMPTY);
     } else if (contextURLasString.endsWith("/$deletedEntity")) {
-      builder.suffix(Suffix.DELTA_DELETED_ENTITY);
+      contextUrl.suffix(Suffix.DELTA_DELETED_ENTITY);
       contextURLasString = contextURLasString.replace("/$deletedEntity", StringUtils.EMPTY);
     } else if (contextURLasString.endsWith("/$link")) {
-      builder.suffix(Suffix.DELTA_LINK);
+      contextUrl.suffix(Suffix.DELTA_LINK);
       contextURLasString = contextURLasString.replace("/$link", StringUtils.EMPTY);
     } else if (contextURLasString.endsWith("/$deletedLink")) {
-      builder.suffix(Suffix.DELTA_DELETED_LINK);
+      contextUrl.suffix(Suffix.DELTA_DELETED_LINK);
       contextURLasString = contextURLasString.replace("/$deletedLink", StringUtils.EMPTY);
     }
 
-    builder.serviceRoot(URI.create(StringUtils.substringBefore(contextURLasString, Constants.METADATA)));
+    contextUrl.serviceRoot(URI.create(StringUtils.substringBefore(contextURLasString, Constants.METADATA)));
 
     final String rest = StringUtils.substringAfter(contextURLasString, Constants.METADATA + "#");
 
     String firstToken;
-    String entitySetOrSingletonOrType = null;
+    String entitySetOrSingletonOrType;
     if (rest.startsWith("Collection(")) {
       firstToken = rest.substring(0, rest.indexOf(')') + 1);
       entitySetOrSingletonOrType = firstToken;
@@ -86,34 +86,33 @@ public class ContextURLParser {
         entitySetOrSingletonOrType = StringUtils.join(parts, '/');
         final int commaIdx = firstToken.indexOf(',');
         if (commaIdx != -1) {
-          builder.selectList(firstToken.substring(openParIdx + 1, firstToken.length() - 1));
+          contextUrl.selectList(firstToken.substring(openParIdx + 1, firstToken.length() - 1));
         }
       }
     }
-    builder.entitySetOrSingletonOrType(entitySetOrSingletonOrType);
+    contextUrl.entitySetOrSingletonOrType(entitySetOrSingletonOrType);
 
     final int slashIdx = entitySetOrSingletonOrType.lastIndexOf('/');
     if (slashIdx != -1 && entitySetOrSingletonOrType.substring(slashIdx + 1).indexOf('.') != -1) {
-      final String clone = entitySetOrSingletonOrType;
-      builder.entitySetOrSingletonOrType(clone.substring(0, slashIdx));
-      builder.derivedEntity(clone.substring(slashIdx + 1));
+      contextUrl.entitySetOrSingletonOrType(entitySetOrSingletonOrType.substring(0, slashIdx));
+      contextUrl.derivedEntity(entitySetOrSingletonOrType.substring(slashIdx + 1));
     }
 
     if (!firstToken.equals(rest)) {
       final String[] pathElems = StringUtils.substringAfter(rest, "/").split("/");
       if (pathElems.length > 0 && pathElems[0].length() > 0) {
         if (pathElems[0].indexOf('.') == -1) {
-          builder.navOrPropertyPath(pathElems[0]);
+          contextUrl.navOrPropertyPath(pathElems[0]);
         } else {
-          builder.derivedEntity(pathElems[0]);
+          contextUrl.derivedEntity(pathElems[0]);
         }
 
         if (pathElems.length > 1) {
-          builder.navOrPropertyPath(pathElems[1]);
+          contextUrl.navOrPropertyPath(pathElems[1]);
         }
       }
     }
 
-    return builder.build();
+    return contextUrl.build();
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/461cdbbe/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
index a0d44b9..cc13485 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
@@ -20,13 +20,11 @@ package org.apache.olingo.server.api.serializer;
 
 import java.io.InputStream;
 
-import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.server.api.ODataServerError;
-import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
 
 public interface ODataSerializer {
 
@@ -36,10 +34,10 @@ public interface ODataSerializer {
 
   InputStream metadataDocument(Edm edm) throws ODataSerializerException;
 
-  InputStream entity(EdmEntitySet edmEntitySet, Entity entity, ContextURL contextURL, ExpandItem options)
+  InputStream entity(EdmEntitySet edmEntitySet, Entity entity, ODataSerializerOptions options)
       throws ODataSerializerException;
 
-  InputStream entitySet(EdmEntitySet edmEntitySet, EntitySet entitySet, ContextURL contextURL, ExpandItem options)
+  InputStream entitySet(EdmEntitySet edmEntitySet, EntitySet entitySet, ODataSerializerOptions options)
       throws ODataSerializerException;
 
   /**

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/461cdbbe/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializerOptions.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializerOptions.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializerOptions.java
new file mode 100644
index 0000000..3e23066
--- /dev/null
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializerOptions.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.api.serializer;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.server.api.uri.queryoption.CountOption;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
+
+public class ODataSerializerOptions {
+
+  private ContextURL contextURL;
+  private CountOption count;
+  private ExpandOption expand;
+  private SelectOption select;
+
+  public ContextURL getContextURL() {
+    return contextURL;
+  }
+
+  public CountOption getCount() {
+    return count;
+  }
+
+  public ExpandOption getExpand() {
+    return expand;
+  }
+
+  public SelectOption getSelect() {
+    return select;
+  }
+
+  private ODataSerializerOptions() {}
+
+  public static Builder with() {
+    return new Builder();
+  }
+
+  public static final class Builder {
+
+    private ODataSerializerOptions options;
+
+    private Builder() {
+      options = new ODataSerializerOptions();
+    }
+
+    public Builder contextURL(final ContextURL contextURL) {
+      options.contextURL = contextURL;
+      return this;
+    }
+
+    public Builder count(final CountOption count) {
+      options.count = count;
+      return this;
+    }
+
+    public Builder expand(final ExpandOption expand) {
+      options.expand = expand;
+      return this;
+    }
+
+    public Builder select(final SelectOption select) {
+      options.select = select;
+      return this;
+    }
+
+    public ODataSerializerOptions build() {
+      return options;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/461cdbbe/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
index f3043c1..65b0b3a 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
@@ -24,7 +24,6 @@ import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 
-import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
 import org.apache.olingo.commons.api.edm.Edm;
@@ -32,7 +31,7 @@ import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.ODataSerializerException;
-import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
 import org.apache.olingo.server.core.serializer.xml.MetadataDocumentXmlSerializer;
 import org.slf4j.Logger;
@@ -80,15 +79,15 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
   }
 
   @Override
-  public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity, final ContextURL contextURL,
-      final ExpandItem options) throws ODataSerializerException {
+  public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity,
+      final ODataSerializerOptions options) throws ODataSerializerException {
     throw new ODataSerializerException("Entity serialization not implemented for XML format",
         ODataSerializerException.MessageKeys.NOT_IMPLEMENTED);
   }
 
   @Override
   public InputStream entitySet(final EdmEntitySet edmEntitySet, final EntitySet entitySet,
-      final ContextURL contextURL, final ExpandItem options) throws ODataSerializerException {
+      final ODataSerializerOptions options) throws ODataSerializerException {
     throw new ODataSerializerException("Entityset serialization not implemented for XML format",
         ODataSerializerException.MessageKeys.NOT_IMPLEMENTED);
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/461cdbbe/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
index 2e4402b..6ab22b5 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
@@ -45,7 +45,10 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.ODataSerializerException;
+import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
 import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
 import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
 import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper;
@@ -125,24 +128,27 @@ public class ODataJsonSerializer implements ODataSerializer {
 
   @Override
   public InputStream entitySet(final EdmEntitySet edmEntitySet, final EntitySet entitySet,
-      final ContextURL contextURL, final ExpandItem options) throws ODataSerializerException {
+      final ODataSerializerOptions options) throws ODataSerializerException {
     CircleStreamBuffer buffer = new CircleStreamBuffer();
     try {
       JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
       json.writeStartObject();
       if (format != ODataFormat.JSON_NO_METADATA) {
-        if (contextURL == null) {
+        if (options == null || options.getContextURL() == null) {
           throw new ODataSerializerException("ContextURL null!",
               ODataSerializerException.MessageKeys.NO_CONTEXT_URL);
         } else {
-          json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
+          json.writeStringField(Constants.JSON_CONTEXT,
+              ContextURLBuilder.create(options.getContextURL()).toASCIIString());
         }
       }
-      if (entitySet.getCount() != null) {
+      if (options != null && options.getCount() != null && options.getCount().getValue()
+          && entitySet.getCount() != null) {
         json.writeNumberField(Constants.JSON_COUNT, entitySet.getCount());
       }
       json.writeFieldName(Constants.VALUE);
-      writeEntitySet(edmEntitySet.getEntityType(), entitySet, options, json);
+      writeEntitySet(edmEntitySet.getEntityType(), entitySet,
+          options == null ? null : options.getExpand(), options == null ? null : options.getSelect(), json);
       if (entitySet.getNext() != null) {
         json.writeStringField(Constants.JSON_NEXT_LINK, entitySet.getNext().toASCIIString());
       }
@@ -155,8 +161,9 @@ public class ODataJsonSerializer implements ODataSerializer {
   }
 
   @Override
-  public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity, final ContextURL contextURL,
-      final ExpandItem options) throws ODataSerializerException {
+  public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity,
+      final ODataSerializerOptions options) throws ODataSerializerException {
+    final ContextURL contextURL = options == null ? null : options.getContextURL();
     if (format != ODataFormat.JSON_NO_METADATA && contextURL == null) {
       throw new ODataSerializerException("ContextURL null!",
           ODataSerializerException.MessageKeys.NO_CONTEXT_URL);
@@ -164,7 +171,8 @@ public class ODataJsonSerializer implements ODataSerializer {
     CircleStreamBuffer buffer = new CircleStreamBuffer();
     try {
       JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
-      writeEntity(edmEntitySet.getEntityType(), entity, contextURL, options, json);
+      writeEntity(edmEntitySet.getEntityType(), entity, contextURL,
+          options == null ? null : options.getExpand(), options == null ? null : options.getSelect(), json);
       json.close();
     } catch (final IOException e) {
       throw new ODataSerializerException("An I/O exception occurred.", e,
@@ -174,16 +182,18 @@ public class ODataJsonSerializer implements ODataSerializer {
   }
 
   protected void writeEntitySet(final EdmEntityType entityType, final EntitySet entitySet,
-      final ExpandItem options, final JsonGenerator json) throws IOException, ODataSerializerException {
+      final ExpandOption expand, final SelectOption select, final JsonGenerator json)
+      throws IOException, ODataSerializerException {
     json.writeStartArray();
     for (final Entity entity : entitySet.getEntities()) {
-      writeEntity(entityType, entity, null, options, json);
+      writeEntity(entityType, entity, null, expand, select, json);
     }
     json.writeEndArray();
   }
 
   protected void writeEntity(final EdmEntityType entityType, final Entity entity, final ContextURL contextURL,
-      final ExpandItem options, final JsonGenerator json) throws IOException, ODataSerializerException {
+      final ExpandOption expand, final SelectOption select, final JsonGenerator json)
+      throws IOException, ODataSerializerException {
     json.writeStartObject();
     if (format != ODataFormat.JSON_NO_METADATA) {
       if (contextURL != null) {
@@ -201,64 +211,68 @@ public class ODataJsonSerializer implements ODataSerializer {
         }
       }
     }
-    writeProperties(entityType, entity, options, json);
-    writeNavigationProperties(entityType, entity, options, json);
+    writeProperties(entityType, entity, select, json);
+    writeNavigationProperties(entityType, entity, expand, json);
     json.writeEndObject();
   }
 
-  protected void writeProperties(final EdmEntityType entityType, final Entity entity, final ExpandItem options,
-      final JsonGenerator json) throws IOException, ODataSerializerException {
-    final boolean all = ExpandSelectHelper.isAll(options);
+  protected void writeProperties(final EdmEntityType entityType, final Entity entity, final SelectOption select,
+      JsonGenerator json) throws IOException, ODataSerializerException {
+    final boolean all = ExpandSelectHelper.isAll(select);
     final Set<String> selected = all ? null :
-        ExpandSelectHelper.getSelectedPropertyNames(options.getSelectOption().getSelectItems());
+        ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems());
     for (final String propertyName : entityType.getPropertyNames()) {
       if (all || selected.contains(propertyName)) {
         final EdmProperty edmProperty = (EdmProperty) entityType.getProperty(propertyName);
         final Property property = entity.getProperty(propertyName);
         final Set<List<String>> selectedPaths = all || edmProperty.isPrimitive() ? null :
-            ExpandSelectHelper.getSelectedPaths(options.getSelectOption().getSelectItems(), propertyName);
+            ExpandSelectHelper.getSelectedPaths(select.getSelectItems(), propertyName);
         writeProperty(edmProperty, property, selectedPaths, json);
       }
     }
   }
 
   protected void writeNavigationProperties(final EdmEntityType entityType, final Entity entity,
-      final ExpandItem options, final JsonGenerator json) throws ODataSerializerException, IOException {
-    if (options != null && (options.isRef() || options.getLevelsOption() != null)) {
-      throw new ODataSerializerException("Expand options $ref and $levels are not supported.",
-          ODataSerializerException.MessageKeys.NOT_IMPLEMENTED);
-    }
-    if (ExpandSelectHelper.hasExpand(options)) {
-      final boolean expandAll = ExpandSelectHelper.isExpandAll(options);
+      final ExpandOption expand, final JsonGenerator json) throws ODataSerializerException, IOException {
+    if (ExpandSelectHelper.hasExpand(expand)) {
+      final boolean expandAll = ExpandSelectHelper.isExpandAll(expand);
       final Set<String> expanded = expandAll ? null :
-          ExpandSelectHelper.getExpandedPropertyNames(options.getExpandOption().getExpandItems());
+          ExpandSelectHelper.getExpandedPropertyNames(expand.getExpandItems());
       for (final String propertyName : entityType.getNavigationPropertyNames()) {
         if (expandAll || expanded.contains(propertyName)) {
           final EdmNavigationProperty property = entityType.getNavigationProperty(propertyName);
           final Link navigationLink = entity.getNavigationLink(property.getName());
           final ExpandItem innerOptions = expandAll ? null :
-              ExpandSelectHelper.getExpandItem(options.getExpandOption().getExpandItems(), propertyName);
-          writeExpandedNavigationProperty(property, navigationLink, innerOptions, json);
+              ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
+          if (innerOptions != null && (innerOptions.isRef() || innerOptions.getLevelsOption() != null)) {
+            throw new ODataSerializerException("Expand options $ref and $levels are not supported.",
+                ODataSerializerException.MessageKeys.NOT_IMPLEMENTED);
+          }
+          writeExpandedNavigationProperty(property, navigationLink,
+              innerOptions == null ? null : innerOptions.getExpandOption(),
+              innerOptions == null ? null : innerOptions.getSelectOption(),
+              json);
         }
       }
     }
   }
 
   protected void writeExpandedNavigationProperty(final EdmNavigationProperty property, final Link navigationLink,
-      final ExpandItem innerOptions, JsonGenerator json) throws IOException, ODataSerializerException {
+      final ExpandOption innerExpand, final SelectOption innerSelect, JsonGenerator json)
+      throws IOException, ODataSerializerException {
     json.writeFieldName(property.getName());
     if (property.isCollection()) {
       if (navigationLink == null || navigationLink.getInlineEntitySet() == null) {
         json.writeStartArray();
         json.writeEndArray();
       } else {
-        writeEntitySet(property.getType(), navigationLink.getInlineEntitySet(), innerOptions, json);
+        writeEntitySet(property.getType(), navigationLink.getInlineEntitySet(), innerExpand, innerSelect, json);
       }
     } else {
       if (navigationLink == null || navigationLink.getInlineEntity() == null) {
         json.writeNull();
       } else {
-        writeEntity(property.getType(), navigationLink.getInlineEntity(), null, innerOptions, json);
+        writeEntity(property.getType(), navigationLink.getInlineEntity(), null, innerExpand, innerSelect, json);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/461cdbbe/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
index 09bb50d..c5dcbbe 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
@@ -28,17 +28,17 @@ import org.apache.olingo.server.api.uri.UriResource;
 import org.apache.olingo.server.api.uri.UriResourceNavigation;
 import org.apache.olingo.server.api.uri.UriResourceProperty;
 import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectItem;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 
 public abstract class ExpandSelectHelper {
 
-  public static boolean isAll(final ExpandItem options) {
-    if (options == null || options.getSelectOption() == null
-        || options.getSelectOption().getSelectItems() == null
-        || options.getSelectOption().getSelectItems().isEmpty()) {
+  public static boolean isAll(final SelectOption select) {
+    if (select == null || select.getSelectItems() == null || select.getSelectItems().isEmpty()) {
       return true;
     } else {
-      for (final SelectItem item : options.getSelectOption().getSelectItems()) {
+      for (final SelectItem item : select.getSelectItems()) {
         if (item.isStar()) {
           return true;
         }
@@ -81,13 +81,12 @@ public abstract class ExpandSelectHelper {
     return selectedPaths.isEmpty() ? null : selectedPaths;
   }
 
-  public static boolean hasExpand(final ExpandItem options) {
-    return options != null && options.getExpandOption() != null && options.getExpandOption().getExpandItems() != null
-        && !options.getExpandOption().getExpandItems().isEmpty();
+  public static boolean hasExpand(final ExpandOption expand) {
+    return expand != null && expand.getExpandItems() != null && !expand.getExpandItems().isEmpty();
   }
 
-  public static boolean isExpandAll(final ExpandItem options) {
-    for (final ExpandItem item : options.getExpandOption().getExpandItems()) {
+  public static boolean isExpandAll(final ExpandOption expand) {
+    for (final ExpandItem item : expand.getExpandItems()) {
       if (item.isStar()) {
         return true;
       }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/461cdbbe/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
index 6993d3b..7a01643 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
@@ -34,14 +34,14 @@ public class ContextURLBuilderTest {
 
   @Test
   public void buildServiceDocument() {
-    ContextURL contextURL = ContextURL.Builder.create()
+    ContextURL contextURL = ContextURL.with()
         .serviceRoot(URI.create("http://host/service/")).build();
     assertEquals("http://host/service/$metadata", ContextURLBuilder.create(contextURL).toASCIIString());
   }
 
   @Test
   public void buildRelative() {
-    ContextURL contextURL = ContextURL.Builder.create().build();
+    ContextURL contextURL = ContextURL.with().build();
     assertEquals("$metadata", ContextURLBuilder.create(contextURL).toASCIIString());
   }
 
@@ -49,7 +49,7 @@ public class ContextURLBuilderTest {
   public void buildEntitySet() {
     EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
     Mockito.when(entitySet.getName()).thenReturn("Customers");
-    ContextURL contextURL = ContextURL.Builder.create().serviceRoot(URI.create("http://host/service/"))
+    ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
         .entitySet(entitySet)
         .build();
     assertEquals("http://host/service/$metadata#Customers", ContextURLBuilder.create(contextURL).toASCIIString());
@@ -61,7 +61,7 @@ public class ContextURLBuilderTest {
     Mockito.when(entitySet.getName()).thenReturn("Customers");
     EdmEntityType derivedType = Mockito.mock(EdmEntityType.class);
     Mockito.when(derivedType.getFullQualifiedName()).thenReturn(new FullQualifiedName("Model", "VipCustomer"));
-    ContextURL contextURL = ContextURL.Builder.create().serviceRoot(URI.create("http://host/service/"))
+    ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
         .entitySet(entitySet)
         .derived(derivedType)
         .build();
@@ -73,7 +73,7 @@ public class ContextURLBuilderTest {
   public void buildDerivedEntitySetWithoutEntitySet() {
     EdmEntityType derivedType = Mockito.mock(EdmEntityType.class);
     Mockito.when(derivedType.getFullQualifiedName()).thenReturn(new FullQualifiedName("Model", "VipCustomer"));
-    ContextURLBuilder.create(ContextURL.Builder.create().derived(derivedType).build());
+    ContextURLBuilder.create(ContextURL.with().derived(derivedType).build());
   }
 
   @Test
@@ -82,7 +82,7 @@ public class ContextURLBuilderTest {
     Mockito.when(entitySet.getName()).thenReturn("Customers");
     EdmEntityType derivedType = Mockito.mock(EdmEntityType.class);
     Mockito.when(derivedType.getFullQualifiedName()).thenReturn(new FullQualifiedName("Model", "VipCustomer"));
-    ContextURL contextURL = ContextURL.Builder.create().serviceRoot(URI.create("http://host/service/"))
+    ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
         .entitySet(entitySet)
         .derived(derivedType)
         .suffix(Suffix.ENTITY)
@@ -93,12 +93,12 @@ public class ContextURLBuilderTest {
 
   @Test(expected = IllegalArgumentException.class)
   public void buildSuffixWithoutEntitySet() {
-    ContextURLBuilder.create(ContextURL.Builder.create().suffix(Suffix.ENTITY).build());
+    ContextURLBuilder.create(ContextURL.with().suffix(Suffix.ENTITY).build());
   }
 
   @Test
   public void buildReference() {
-    ContextURL contextURL = ContextURL.Builder.create().suffix(Suffix.REFERENCE).build();
+    ContextURL contextURL = ContextURL.with().suffix(Suffix.REFERENCE).build();
     assertEquals("$metadata#$ref", ContextURLBuilder.create(contextURL).toASCIIString());
   }
 
@@ -106,7 +106,7 @@ public class ContextURLBuilderTest {
   public void buildReferenceWithEntitySet() {
     EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
     Mockito.when(entitySet.getName()).thenReturn("Customers");
-    ContextURLBuilder.create(ContextURL.Builder.create().entitySet(entitySet).suffix(Suffix.REFERENCE).build());
+    ContextURLBuilder.create(ContextURL.with().entitySet(entitySet).suffix(Suffix.REFERENCE).build());
   }
 
   @Test
@@ -116,7 +116,7 @@ public class ContextURLBuilderTest {
     EdmEntityType derivedType = Mockito.mock(EdmEntityType.class);
     Mockito.when(derivedType.getFullQualifiedName()).thenReturn(
         new FullQualifiedName("Namensräumchen", "UnüblicherName"));
-    ContextURL contextURL = ContextURL.Builder.create().entitySet(entitySet).derived(derivedType).build();
+    ContextURL contextURL = ContextURL.with().entitySet(entitySet).derived(derivedType).build();
     assertEquals("$metadata#Entit%C3%A4ten/Namensr%C3%A4umchen.Un%C3%BCblicherName",
         ContextURLBuilder.create(contextURL).toString());
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/461cdbbe/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index 3917fae..950ce95 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@ -36,6 +36,7 @@ import org.apache.olingo.server.api.ODataTranslatedException;
 import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
 import org.apache.olingo.server.api.processor.EntityProcessor;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoResource;
 import org.apache.olingo.server.api.uri.UriResource;
@@ -73,7 +74,12 @@ public class TechnicalProcessor implements EntityCollectionProcessor, EntityProc
         response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
       } else {
         ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(requestedContentType));
-        response.setContent(serializer.entitySet(edmEntitySet, entitySet, getContextUrl(edmEntitySet, false), null));
+        response.setContent(serializer.entitySet(edmEntitySet, entitySet,
+            ODataSerializerOptions.with()
+                .contextURL(getContextUrl(edmEntitySet, false))
+                .count(uriInfo.getCountOption())
+                .expand(uriInfo.getExpandOption()).select(uriInfo.getSelectOption())
+                .build()));
         response.setStatusCode(HttpStatusCode.OK.getStatusCode());
         response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
       }
@@ -100,7 +106,13 @@ public class TechnicalProcessor implements EntityCollectionProcessor, EntityProc
         response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
       } else {
         ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(requestedContentType));
-        response.setContent(serializer.entity(edmEntitySet, entity, getContextUrl(edmEntitySet, true), null));
+        response.setContent(serializer.entity(edmEntitySet, entity,
+            ODataSerializerOptions.with()
+                .contextURL(getContextUrl(edmEntitySet, true))
+                .count(uriInfo.getCountOption())
+                .expand(uriInfo.getExpandOption())
+                .select(uriInfo.getSelectOption())
+                .build()));
         response.setStatusCode(HttpStatusCode.OK.getStatusCode());
         response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
       }
@@ -128,12 +140,10 @@ public class TechnicalProcessor implements EntityCollectionProcessor, EntityProc
   private boolean validateOptions(final UriInfoResource uriInfo) {
     return uriInfo.getCountOption() == null
         && uriInfo.getCustomQueryOptions().isEmpty()
-        && uriInfo.getExpandOption() == null
         && uriInfo.getFilterOption() == null
         && uriInfo.getIdOption() == null
         && uriInfo.getOrderByOption() == null
         && uriInfo.getSearchOption() == null
-        && uriInfo.getSelectOption() == null
         && uriInfo.getSkipOption() == null
         && uriInfo.getSkipTokenOption() == null
         && uriInfo.getTopOption() == null;
@@ -158,6 +168,6 @@ public class TechnicalProcessor implements EntityCollectionProcessor, EntityProc
   }
 
   private ContextURL getContextUrl(final EdmEntitySet entitySet, final boolean isSingleEntity) {
-    return ContextURL.Builder.create().entitySet(entitySet).suffix(isSingleEntity ? Suffix.ENTITY : null).build();
+    return ContextURL.with().entitySet(entitySet).suffix(isSingleEntity ? Suffix.ENTITY : null).build();
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/461cdbbe/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
index 66363ae..213c26d 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
@@ -43,10 +43,12 @@ import org.apache.olingo.commons.api.format.ODataFormat;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.ODataSerializerException;
+import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
 import org.apache.olingo.server.api.uri.UriInfoResource;
 import org.apache.olingo.server.api.uri.UriResource;
 import org.apache.olingo.server.api.uri.UriResourceNavigation;
 import org.apache.olingo.server.api.uri.UriResourceProperty;
+import org.apache.olingo.server.api.uri.queryoption.CountOption;
 import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectItem;
@@ -71,8 +73,9 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet, entity,
-        ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
-        null);
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build());
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
@@ -102,7 +105,9 @@ public class ODataJsonSerializerTest {
     Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     entity.getProperties().retainAll(Arrays.asList(entity.getProperties().get(0)));
     final String resultString = IOUtils.toString(serializer.entity(edmEntitySet, entity,
-        ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null));
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build()));
     final String expectedResult = "{\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
         + "\"PropertyInt16\":32767,"
         + "\"PropertyString\":null,\"PropertyBoolean\":null,"
@@ -121,7 +126,9 @@ public class ODataJsonSerializerTest {
     Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     entity.getProperties().clear();
     serializer.entity(edmEntitySet, entity,
-        ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null);
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build());
   }
 
   @Test
@@ -131,7 +138,9 @@ public class ODataJsonSerializerTest {
     entity.getProperties().get(0).setValue(ValueType.PRIMITIVE, false);
     try {
       serializer.entity(edmEntitySet, entity,
-          ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null);
+          ODataSerializerOptions.with()
+              .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+              .build());
       Assert.fail("Expected exception not thrown!");
     } catch (final ODataSerializerException e) {
       Assert.assertEquals(ODataSerializerException.MessageKeys.WRONG_PROPERTY_VALUE, e.getMessageKey());
@@ -147,8 +156,13 @@ public class ODataJsonSerializerTest {
     EntitySet entitySet = data.readAll(edmEntitySet);
     entitySet.setCount(entitySet.getEntities().size());
     entitySet.setNext(URI.create("/next"));
+    CountOption countOption = Mockito.mock(CountOption.class);
+    Mockito.when(countOption.getValue()).thenReturn(true);
     InputStream result = serializer.entitySet(edmEntitySet, entitySet,
-        ContextURL.Builder.create().entitySet(edmEntitySet).build(), null);
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).build())
+            .count(countOption)
+            .build());
     final String resultString = IOUtils.toString(result);
 
     Assert.assertThat(resultString, CoreMatchers.startsWith("{"
@@ -170,8 +184,10 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet, entity,
-        ContextURL.Builder.create().serviceRoot(URI.create("http://host/service/"))
-            .entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null);
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().serviceRoot(URI.create("http://host/service/"))
+                .entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build());
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"http://host/service/$metadata#ESCollAllPrim/$entity\","
@@ -204,7 +220,9 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCompAllPrim");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet, entity,
-        ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null);
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build());
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"$metadata#ESCompAllPrim/$entity\","
@@ -235,7 +253,9 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet, entity,
-        ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null);
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build());
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\","
@@ -256,7 +276,9 @@ public class ODataJsonSerializerTest {
     Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     entity.getProperties().retainAll(Arrays.asList(entity.getProperties().get(0)));
     final String resultString = IOUtils.toString(serializer.entity(edmEntitySet, entity,
-        ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null));
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build()));
     final String expectedResult = "{\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\","
         + "\"PropertyInt16\":32767,"
         + "\"CollPropertyString\":null,\"PropertyComp\":null,\"CollPropertyComp\":null}";
@@ -268,7 +290,7 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESTwoPrim");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA)
-        .entity(edmEntitySet, entity, null, null);
+        .entity(edmEntitySet, entity, null);
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}";
     Assert.assertEquals(expectedResult, resultString);
@@ -279,7 +301,9 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESTwoPrim");
     final EntitySet entitySet = data.readAll(edmEntitySet);
     InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA)
-        .entitySet(edmEntitySet, entitySet, ContextURL.Builder.create().entitySet(edmEntitySet).build(), null);
+        .entitySet(edmEntitySet, entitySet,
+            ODataSerializerOptions.with()
+                .contextURL(ContextURL.with().entitySet(edmEntitySet).build()).build());
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{\"value\":["
         + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"},"
@@ -295,7 +319,9 @@ public class ODataJsonSerializerTest {
     Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     entity.setMediaETag("theMediaETag");
     final String resultString = IOUtils.toString(serializer.entity(edmEntitySet, entity,
-        ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null));
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build()));
     final String expectedResult = "{\"@odata.context\":\"$metadata#ESMedia/$entity\","
         + "\"@odata.mediaEtag\":\"theMediaETag\",\"@odata.mediaContentType\":\"image/png\","
         + "\"PropertyInt16\":1}";
@@ -307,7 +333,8 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMedia");
     final EntitySet entitySet = data.readAll(edmEntitySet);
     final String resultString = IOUtils.toString(serializer.entitySet(edmEntitySet, entitySet,
-        ContextURL.Builder.create().entitySet(edmEntitySet).build(), null));
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).build()).build()));
     final String expectedResult = "{\"@odata.context\":\"$metadata#ESMedia\",\"value\":["
         + "{\"@odata.mediaContentType\":\"image/png\",\"PropertyInt16\":1},"
         + "{\"@odata.mediaContentType\":\"image/bmp\",\"PropertyInt16\":2},"
@@ -323,14 +350,15 @@ public class ODataJsonSerializerTest {
     final SelectItem selectItem1 = mockSelectItem(edmEntitySet, "PropertyDate");
     final SelectItem selectItem2 = mockSelectItem(edmEntitySet, "PropertyBoolean");
     final SelectOption select = mockSelectOption(Arrays.asList(selectItem1, selectItem2, selectItem2));
-    ExpandItem options = Mockito.mock(ExpandItem.class);
-    Mockito.when(options.getSelectOption()).thenReturn(select);
     InputStream result =
         new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer
             .entity(edmEntitySet, entity,
-                null, // ContextURL.Builder.create().entitySet(edmEntitySet).selectList("PropertyBoolean,PropertyDate")
-                      //     .suffix(Suffix.ENTITY).build(),
-                options);
+                ODataSerializerOptions.with()
+                    .contextURL(null)
+                // ContextURL.Builder.with().entitySet(edmEntitySet).selectList("PropertyBoolean,PropertyDate")
+                //     .suffix(Suffix.ENTITY).build(),
+                    .select(select)
+                    .build());
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         // + "\"@odata.context\":\"$metadata#ESAllPrim(PropertyBoolean,PropertyDate)/$entity\","
@@ -346,11 +374,11 @@ public class ODataJsonSerializerTest {
     SelectItem selectItem2 = Mockito.mock(SelectItem.class);
     Mockito.when(selectItem2.isStar()).thenReturn(true);
     final SelectOption select = mockSelectOption(Arrays.asList(selectItem1, selectItem2));
-    ExpandItem options = Mockito.mock(ExpandItem.class);
-    Mockito.when(options.getSelectOption()).thenReturn(select);
     InputStream result = serializer.entity(edmEntitySet, entity,
-        ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
-        options);
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .select(select)
+            .build());
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{\"@odata.context\":\"$metadata#ESTwoPrim/$entity\","
         + "\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}";
@@ -363,14 +391,15 @@ public class ODataJsonSerializerTest {
     final EntitySet entitySet = data.readAll(edmEntitySet);
     final SelectOption select = mockSelectOption(Arrays.asList(
         mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp", "PropertyString")));
-    ExpandItem options = Mockito.mock(ExpandItem.class);
-    Mockito.when(options.getSelectOption()).thenReturn(select);
     InputStream result =
         new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer
             .entitySet(edmEntitySet, entitySet,
-                null, // ContextURL.Builder.create().entitySet(edmEntitySet)
-                      //     .selectList("PropertyComp/PropertyComp/PropertyString").build(),
-                options);
+                ODataSerializerOptions.with()
+                    .contextURL(null)
+                    // ContextURL.Builder.with().entitySet(edmEntitySet)
+                    //     .selectList("PropertyComp/PropertyComp/PropertyString").build(),
+                    .select(select)
+                    .build());
     final String resultString = IOUtils.toString(result);
     Assert.assertEquals("{"
         // + "\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp/PropertyString)\","
@@ -387,14 +416,15 @@ public class ODataJsonSerializerTest {
     final SelectOption select = mockSelectOption(Arrays.asList(
         mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp", "PropertyString"),
         mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp")));
-    ExpandItem options = Mockito.mock(ExpandItem.class);
-    Mockito.when(options.getSelectOption()).thenReturn(select);
     InputStream result =
         new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer
             .entitySet(edmEntitySet, entitySet,
-                null, // ContextURL.Builder.create().entitySet(edmEntitySet)
-                      //     .selectList("PropertyComp/PropertyComp").build(),
-                options);
+                ODataSerializerOptions.with()
+                    .contextURL(null)
+                    // ContextURL.Builder.with().entitySet(edmEntitySet)
+                    //     .selectList("PropertyComp/PropertyComp").build()
+                    .select(select)
+                    .build());
     final String resultString = IOUtils.toString(result);
     Assert.assertEquals("{"
     //    + "\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp)\","
@@ -410,11 +440,11 @@ public class ODataJsonSerializerTest {
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(3);
     final ExpandOption expand = mockExpandOption(Arrays.asList(
         mockExpandItem(edmEntitySet, "NavPropertyETAllPrimOne")));
-    ExpandItem options = Mockito.mock(ExpandItem.class);
-    Mockito.when(options.getExpandOption()).thenReturn(expand);
     InputStream result = serializer.entity(edmEntitySet, entity,
-        ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
-        options);
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .expand(expand)
+            .build());
     final String resultString = IOUtils.toString(result);
     Assert.assertEquals("{\"@odata.context\":\"$metadata#ESTwoPrim/$entity\","
         + "\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\","
@@ -447,13 +477,14 @@ public class ODataJsonSerializerTest {
     ExpandItem expandItem = mockExpandItem(edmEntitySet, "NavPropertyETAllPrimOne");
     Mockito.when(expandItem.getSelectOption()).thenReturn(select);
     final ExpandOption expand = mockExpandOption(Arrays.asList(expandItem));
-    ExpandItem options = Mockito.mock(ExpandItem.class);
-    Mockito.when(options.getExpandOption()).thenReturn(expand);
     InputStream result =
         new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer
             .entity(edmEntitySet, entity,
-                null, // ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
-                options);
+                ODataSerializerOptions.with()
+                    .contextURL(null)
+                    // ContextURL.Builder.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()
+                    .expand(expand)
+                    .build());
     final String resultString = IOUtils.toString(result);
     Assert.assertEquals("{"
         // + "\"@odata.context\":\"$metadata#ESTwoPrim(NavPropertyETAllPrimOne(PropertyDate))/$entity\","
@@ -471,14 +502,15 @@ public class ODataJsonSerializerTest {
     Mockito.when(expandItemAll.isStar()).thenReturn(true);
     final ExpandOption expand = mockExpandOption(Arrays.asList(expandItem, expandItem, expandItemAll));
     final SelectOption select = mockSelectOption(Arrays.asList(mockSelectItem(edmEntitySet, "PropertySByte")));
-    ExpandItem options = Mockito.mock(ExpandItem.class);
-    Mockito.when(options.getExpandOption()).thenReturn(expand);
-    Mockito.when(options.getSelectOption()).thenReturn(select);
     InputStream result =
         new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer
             .entity(edmEntitySet, entity,
-                null, // ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
-                options);
+                ODataSerializerOptions.with()
+                    .contextURL(null)
+                    // ContextURL.Builder.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()
+                    .expand(expand)
+                    .select(select)
+                    .build());
     final String resultString = IOUtils.toString(result);
     Assert.assertEquals("{"
         // + "\"@odata.context\":\"$metadata#ESAllPrim(PropertySByte)/$entity\","
@@ -496,14 +528,15 @@ public class ODataJsonSerializerTest {
     Mockito.when(expandItemAll.isStar()).thenReturn(true);
     final ExpandOption expand = mockExpandOption(Arrays.asList(expandItemAll));
     final SelectOption select = mockSelectOption(Arrays.asList(mockSelectItem(edmEntitySet, "PropertyTimeOfDay")));
-    ExpandItem options = Mockito.mock(ExpandItem.class);
-    Mockito.when(options.getExpandOption()).thenReturn(expand);
-    Mockito.when(options.getSelectOption()).thenReturn(select);
     InputStream result =
         new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer
             .entity(edmEntitySet, entity,
-                null, // ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
-                options);
+                ODataSerializerOptions.with()
+                    .contextURL(null)
+                    // ContextURL.Builder.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()
+                    .expand(expand)
+                    .select(select)
+                    .build());
     final String resultString = IOUtils.toString(result);
     Assert.assertEquals("{"
         // + "\"@odata.context\":\"$metadata#ESAllPrim(PropertyTimeOfDay)/$entity\","
@@ -526,13 +559,14 @@ public class ODataJsonSerializerTest {
         mockSelectItem(innerEntitySet, "PropertyInt32")));
     Mockito.when(expandItemFirst.getSelectOption()).thenReturn(select);
     final ExpandOption expand = mockExpandOption(Arrays.asList(expandItemFirst));
-    ExpandItem options = Mockito.mock(ExpandItem.class);
-    Mockito.when(options.getExpandOption()).thenReturn(expand);
     InputStream result =
         new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer
             .entity(edmEntitySet, entity,
-                null, // ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
-                options);
+                ODataSerializerOptions.with()
+                    .contextURL(null)
+                    // ContextURL.Builder.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()
+                    .expand(expand)
+                    .build());
     final String resultString = IOUtils.toString(result);
     Assert.assertEquals("{"
         // + "\"@odata.context\":\"$metadata#ESTwoPrim(NavPropertyETAllPrimMany(PropertyInt32))/$entity\","