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/06/17 14:58:56 UTC

[3/3] git commit: [OLINGO-317] Refactored ContentType

[OLINGO-317] Refactored ContentType


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

Branch: refs/heads/Olingo-317_DeSerializerRefactoring
Commit: ab6fd5e2b8b2b01731c2ba771763e6b126baa28b
Parents: 176bee4
Author: Michael Bolz <mi...@sap.com>
Authored: Tue Jun 17 14:53:44 2014 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Tue Jun 17 14:53:44 2014 +0200

----------------------------------------------------------------------
 .../commons/AbstractPersistenceManager.java     |   6 +-
 .../proxy/commons/EntityInvocationHandler.java  |  12 +-
 .../TransactionalPersistenceManagerImpl.java    |   3 +-
 .../org/apache/olingo/fit/AbstractServices.java |   8 +-
 .../olingo/fit/v3/EntityRetrieveTestITCase.java |   2 +-
 .../olingo/fit/v3/EntitySetTestITCase.java      |   4 +-
 .../olingo/fit/v3/MediaEntityTestITCase.java    |   2 +-
 .../olingo/fit/v3/PropertyTestITCase.java       |   2 +-
 .../olingo/fit/v3/QueryOptionsTestITCase.java   |   2 +-
 .../olingo/fit/v4/AuthBatchTestITCase.java      |   6 +-
 .../apache/olingo/fit/v4/BatchTestITCase.java   |   2 +-
 .../olingo/fit/v4/ConformanceTestITCase.java    |   6 +-
 .../olingo/fit/v4/EntityRetrieveTestITCase.java |   2 +-
 .../olingo/fit/v4/EntitySetTestITCase.java      |   4 +-
 .../olingo/fit/v4/PropertyValueTestITCase.java  |   4 +-
 .../olingo/fit/v4/QueryOptionsTestITCase.java   |   2 +-
 .../olingo/client/api/CommonConfiguration.java  |   9 +-
 .../olingo/client/core/Configuration.java       |   6 +-
 .../request/AbstractODataBasicRequest.java      |   2 +-
 .../request/AbstractODataRequest.java           |   9 +-
 .../request/batch/ODataBatchUtilities.java      |   6 +-
 .../request/batch/v3/ODataBatchRequestImpl.java |   2 +-
 .../request/batch/v4/ODataBatchRequestImpl.java |   2 +-
 .../invoke/AbstractODataInvokeRequest.java      |   6 +-
 .../AbstractODataStreamedEntityRequest.java     |   4 +-
 .../commons/api/domain/ODataLinkType.java       |   8 +-
 .../olingo/commons/api/format/ContentType.java  | 707 ++++++++++++++++++-
 .../olingo/commons/api/format/ODataFormat.java  | 137 ++--
 .../core/serialization/AtomSerializer.java      |   2 +-
 .../tecsvc/processor/SampleJsonProcessor.java   |   4 +-
 30 files changed, 832 insertions(+), 139 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
index 492c751..d53e68e 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
@@ -354,9 +354,9 @@ abstract class AbstractPersistenceManager implements PersistenceManager {
     final ODataMediaEntityUpdateRequest<?> req =
             factory.getClient().getCUDRequestFactory().getMediaEntityUpdateRequest(uri, input);
 
-    req.setContentType(StringUtils.isBlank(handler.getEntity().getMediaContentType())
-            ? ODataFormat.WILDCARD.toString()
-            : ODataFormat.fromString(handler.getEntity().getMediaContentType()).toString());
+    if (StringUtils.isNotBlank(handler.getEntity().getMediaContentType())) {
+      req.setContentType(ODataFormat.fromString(handler.getEntity().getMediaContentType()).toString());
+    }
 
     if (StringUtils.isNotBlank(handler.getETag())) {
       req.setIfMatch(handler.getETag());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
index aa81921..531353c 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
@@ -320,13 +320,11 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
             && typeRef.getAnnotation(EntityType.class).hasStream()
             && contentSource != null) {
 
-      final String contentType =
-              StringUtils.isBlank(getEntity().getMediaContentType()) ? "*/*" : getEntity().getMediaContentType();
-
-      final ODataMediaRequest retrieveReq = getClient().getRetrieveRequestFactory().
-              getMediaEntityRequest(contentSource);
-      retrieveReq.setFormat(ODataFormat.fromString(contentType));
-
+      final ODataMediaRequest retrieveReq = getClient().getRetrieveRequestFactory()
+          .getMediaEntityRequest(contentSource);
+      if (StringUtils.isNotBlank(getEntity().getMediaContentType())) {
+        retrieveReq.setFormat(ODataFormat.fromString(getEntity().getMediaContentType()));
+      }
       this.stream = retrieveReq.execute().getBody();
     }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
index 73a3f29..1165830 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
@@ -54,7 +54,8 @@ public class TransactionalPersistenceManagerImpl extends AbstractPersistenceMana
   protected void doFlush(final PersistenceChanges changes, final TransactionItems items) {
     final CommonODataBatchRequest request =
             factory.getClient().getBatchRequestFactory().getBatchRequest(factory.getClient().getServiceRoot());
-    ((ODataRequest) request).setAccept(factory.getClient().getConfiguration().getDefaultBatchAcceptFormat());
+    String accept = factory.getClient().getConfiguration().getDefaultBatchAcceptFormat().toContentTypeString();
+    ((ODataRequest) request).setAccept(accept);
 
     final BatchManager streamManager = (BatchManager) ((ODataStreamedRequest) request).payloadManager();
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java
----------------------------------------------------------------------
diff --git a/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java b/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java
index f701b2a..4db7659 100644
--- a/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java
+++ b/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java
@@ -123,6 +123,8 @@ public abstract class AbstractServices {
   private static final Pattern REF_PATTERN = Pattern.compile("([$]\\d+)");
 
   protected static final String BOUNDARY = "batch_243234_25424_ef_892u748";
+  protected static final String MULTIPART_MIXED = "multipart/mixed";//ContentType.MULTIPART_MIXED.toContentTypeString();
+  protected static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
 
   protected final ODataServiceVersion version;
   protected final Metadata metadata;
@@ -194,8 +196,8 @@ public abstract class AbstractServices {
 
   @POST
   @Path("/$batch")
-  @Consumes(ContentType.MULTIPART_MIXED)
-  @Produces(ContentType.APPLICATION_OCTET_STREAM + ";boundary=" + BOUNDARY)
+  @Consumes(MULTIPART_MIXED)
+  @Produces(APPLICATION_OCTET_STREAM + ";boundary=" + BOUNDARY)
   public Response batch(
           @HeaderParam("Authorization") @DefaultValue(StringUtils.EMPTY) String authorization,
           @HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer,
@@ -611,7 +613,7 @@ public abstract class AbstractServices {
       final String entityKey;
       if (xml.isMediaContent(entitySetName)) {
         entry = new EntityImpl();
-        entry.setMediaContentType(ContentType.WILDCARD);
+        entry.setMediaContentType(ContentType.APPLICATION_OCTET_STREAM.toContentTypeString());
         entry.setType(entitySet.getType());
 
         entityKey = xml.getDefaultEntryKey(entitySetName, entry);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v3/EntityRetrieveTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v3/EntityRetrieveTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v3/EntityRetrieveTestITCase.java
index 832b538..39fc464 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v3/EntityRetrieveTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v3/EntityRetrieveTestITCase.java
@@ -150,7 +150,7 @@ public class EntityRetrieveTestITCase extends AbstractTestITCase {
             appendEntitySetSegment("Car").appendKeySegment(16);
 
     final ODataRawRequest req = client.getRetrieveRequestFactory().getRawRequest(uriBuilder.build());
-    req.setFormat(format.toString(client.getServiceVersion()));
+    req.setFormat(format.getContentType(client.getServiceVersion()).toContentTypeString());
 
     final ODataRawResponse res = req.execute();
     assertNotNull(res);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v3/EntitySetTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v3/EntitySetTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v3/EntitySetTestITCase.java
index 61acf0a..83a0a5a 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v3/EntitySetTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v3/EntitySetTestITCase.java
@@ -150,7 +150,7 @@ public class EntitySetTestITCase extends AbstractTestITCase {
     uriBuilder.appendEntitySetSegment("Product").inlineCount(URIBuilder.InlineCount.allpages);
 
     final ODataRawRequest req = client.getRetrieveRequestFactory().getRawRequest(uriBuilder.build());
-    req.setFormat(format.toString(client.getServiceVersion()));
+    req.setFormat(format.getContentType(client.getServiceVersion()).toContentTypeString());
 
     final ODataRawResponse res = req.execute();
     assertNotNull(res);
@@ -164,7 +164,7 @@ public class EntitySetTestITCase extends AbstractTestITCase {
     uriBuilder.appendEntitySetSegment("Car");
 
     final ODataRawRequest req = client.getRetrieveRequestFactory().getRawRequest(uriBuilder.build());
-    req.setFormat(format.toString(client.getServiceVersion()));
+    req.setFormat(format.getContentType(client.getServiceVersion()).toContentTypeString());
 
     final ODataRawResponse res = req.execute();
     assertNotNull(res);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v3/MediaEntityTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v3/MediaEntityTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v3/MediaEntityTestITCase.java
index a29c10f..26f1b29 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v3/MediaEntityTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v3/MediaEntityTestITCase.java
@@ -51,7 +51,7 @@ public class MediaEntityTestITCase extends AbstractTestITCase {
             appendEntitySetSegment("Car").appendKeySegment(12);
 
     final ODataMediaRequest retrieveReq = client.getRetrieveRequestFactory().getMediaEntityRequest(builder.build());
-    retrieveReq.setFormat(ODataFormat.WILDCARD);
+    retrieveReq.setAccept("*/*");
 
     final ODataRetrieveResponse<InputStream> retrieveRes = retrieveReq.execute();
     assertEquals(200, retrieveRes.getStatusCode());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v3/PropertyTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v3/PropertyTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v3/PropertyTestITCase.java
index 6866a06..107fec7 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v3/PropertyTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v3/PropertyTestITCase.java
@@ -348,7 +348,7 @@ public class PropertyTestITCase extends AbstractTestITCase {
             appendEntitySetSegment("Customer").appendKeySegment(-10).appendPropertySegment("BackupContactInfo");
 
     final ODataRawRequest req = client.getRetrieveRequestFactory().getRawRequest(uriBuilder.build());
-    req.setFormat(format.toString(client.getServiceVersion()));
+    req.setFormat(format.getContentType(client.getServiceVersion()).toContentTypeString());
 
     final ODataRawResponse res = req.execute();
     assertNotNull(res);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v3/QueryOptionsTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v3/QueryOptionsTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v3/QueryOptionsTestITCase.java
index 940aa74..09f4a33 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v3/QueryOptionsTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v3/QueryOptionsTestITCase.java
@@ -106,7 +106,7 @@ public class QueryOptionsTestITCase extends AbstractTestITCase {
     final ODataRetrieveResponse<ODataEntity> res = req.execute();
     assertNotNull(res);
     assertTrue(res.getContentType().replaceAll(" ", "").
-            startsWith(ODataFormat.JSON.toString(client.getServiceVersion())));
+            startsWith(ODataFormat.JSON.getContentType(client.getServiceVersion()).toContentTypeString()));
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v4/AuthBatchTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/AuthBatchTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/AuthBatchTestITCase.java
index 73f1578..d09db86 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v4/AuthBatchTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v4/AuthBatchTestITCase.java
@@ -41,7 +41,7 @@ import org.junit.Test;
 
 public class AuthBatchTestITCase extends AbstractTestITCase {
 
-  private final static String ACCEPT = ContentType.APPLICATION_OCTET_STREAM;
+  private final static ContentType ACCEPT = ContentType.APPLICATION_OCTET_STREAM;
 
   @Test
   public void clean() throws EdmPrimitiveTypeException {
@@ -66,8 +66,8 @@ public class AuthBatchTestITCase extends AbstractTestITCase {
   private void batchRequest(final ODataClient client, final String baseURL) throws EdmPrimitiveTypeException {
     // create your request
     final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(baseURL);
-    request.setAccept(ACCEPT);
-    request.addCustomHeader("User-Agent", "Microsoft ADO.NET Data Client xxx");
+    request.setAccept(ACCEPT.toContentTypeString());
+    request.addCustomHeader("User-Agent", "Apache Olingo OData Client");
     request.addCustomHeader(HeaderName.acceptCharset, "UTF-8");
 
     final BatchManager streamManager = request.payloadManager();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v4/BatchTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/BatchTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/BatchTestITCase.java
index c4bac40..a491418 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v4/BatchTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v4/BatchTestITCase.java
@@ -77,7 +77,7 @@ public class BatchTestITCase extends AbstractTestITCase {
 
   private static final int MAX = 10000;
 
-  private final static String ACCEPT = ContentType.APPLICATION_OCTET_STREAM;
+  private final static String ACCEPT = ContentType.APPLICATION_OCTET_STREAM.toContentTypeString();
 
   @Test
   public void stringStreaming() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v4/ConformanceTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/ConformanceTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/ConformanceTestITCase.java
index d2303b2..fc1c2e3 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v4/ConformanceTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v4/ConformanceTestITCase.java
@@ -124,13 +124,13 @@ public class ConformanceTestITCase extends AbstractTestITCase {
 
     // check for Content-Type
     assertEquals(
-            ODataFormat.JSON_FULL_METADATA.toString(ODataServiceVersion.V40),
+            ODataFormat.JSON_FULL_METADATA.getContentType(ODataServiceVersion.V40).toContentTypeString(),
             req.getHeader("Content-Type"));
     assertEquals(
-            ODataFormat.JSON_FULL_METADATA.toString(ODataServiceVersion.V40),
+            ODataFormat.JSON_FULL_METADATA.getContentType(ODataServiceVersion.V40).toContentTypeString(),
             req.getHeader(HeaderName.contentType.toString()));
     assertEquals(
-            ODataFormat.JSON_FULL_METADATA.toString(ODataServiceVersion.V40),
+            ODataFormat.JSON_FULL_METADATA.getContentType(ODataServiceVersion.V40).toContentTypeString(),
             req.getContentType());
 
     final ODataEntity created = req.execute().getBody();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v4/EntityRetrieveTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/EntityRetrieveTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/EntityRetrieveTestITCase.java
index 79b73e9..4937d7a 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v4/EntityRetrieveTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v4/EntityRetrieveTestITCase.java
@@ -172,7 +172,7 @@ public class EntityRetrieveTestITCase extends AbstractTestITCase {
             appendEntitySetSegment("People").appendKeySegment(5);
 
     final ODataRawRequest req = client.getRetrieveRequestFactory().getRawRequest(uriBuilder.build());
-    req.setFormat(format.toString(client.getServiceVersion()));
+    req.setFormat(format.getContentType(client.getServiceVersion()).toContentTypeString());
 
     final ODataRawResponse res = req.execute();
     assertNotNull(res);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v4/EntitySetTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/EntitySetTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/EntitySetTestITCase.java
index a428d3d..0b87fbe 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v4/EntitySetTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v4/EntitySetTestITCase.java
@@ -49,7 +49,7 @@ public class EntitySetTestITCase extends AbstractTestITCase {
     final URIBuilder uriBuilder = client.newURIBuilder(testStaticServiceRootURL).appendEntitySetSegment("People");
 
     final ODataRawRequest req = client.getRetrieveRequestFactory().getRawRequest(uriBuilder.build());
-    req.setFormat(format.toString(client.getServiceVersion()));
+    req.setFormat(format.getContentType(client.getServiceVersion()).toContentTypeString());
 
     final ODataRawResponse res = req.execute();
     assertNotNull(res);
@@ -74,7 +74,7 @@ public class EntitySetTestITCase extends AbstractTestITCase {
             appendEntitySetSegment("People").count(true);
 
     final ODataRawRequest req = client.getRetrieveRequestFactory().getRawRequest(uriBuilder.build());
-    req.setFormat(format.toString(client.getServiceVersion()));
+    req.setFormat(format.getContentType(client.getServiceVersion()).toContentTypeString());
 
     final ODataRawResponse res = req.execute();
     assertNotNull(res);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v4/PropertyValueTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/PropertyValueTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/PropertyValueTestITCase.java
index 14866d0..ed9c3ad 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v4/PropertyValueTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v4/PropertyValueTestITCase.java
@@ -101,7 +101,7 @@ public class PropertyValueTestITCase extends AbstractTestITCase {
     final URIBuilder uriBuilder = client.newURIBuilder(testStaticServiceRootURL).
             appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("PDC");
     final ODataValueRequest req = client.getRetrieveRequestFactory().getPropertyValueRequest(uriBuilder.build());
-    req.setAccept(ODataFormat.ATOM.toString(ODataServiceVersion.V40));
+    req.setAccept(ODataFormat.ATOM.getContentType(ODataServiceVersion.V40).toContentTypeString());
     req.execute().getBody();
   }
 
@@ -110,7 +110,7 @@ public class PropertyValueTestITCase extends AbstractTestITCase {
     final URIBuilder uriBuilder = client.newURIBuilder(testStaticServiceRootURL).
             appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("PDC");
     final ODataValueRequest req = client.getRetrieveRequestFactory().getPropertyValueRequest(uriBuilder.build());
-    req.setAccept(ODataFormat.XML.toString(client.getServiceVersion()));
+    req.setAccept(ODataFormat.XML.getContentType(client.getServiceVersion()).toContentTypeString());
     req.execute().getBody();
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/fit/src/test/java/org/apache/olingo/fit/v4/QueryOptionsTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/QueryOptionsTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/QueryOptionsTestITCase.java
index 19221e9..b55f4ef 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v4/QueryOptionsTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v4/QueryOptionsTestITCase.java
@@ -130,7 +130,7 @@ public class QueryOptionsTestITCase extends AbstractTestITCase {
     final ODataRetrieveResponse<ODataEntity> res = req.execute();
     assertNotNull(res);
     assertTrue(res.getContentType().replaceAll(" ", "").
-            startsWith(ODataFormat.JSON.toString(client.getServiceVersion())));
+            startsWith(ODataFormat.JSON.getContentType(client.getServiceVersion()).toContentTypeString()));
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/client-api/src/main/java/org/apache/olingo/client/api/CommonConfiguration.java
----------------------------------------------------------------------
diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/CommonConfiguration.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/CommonConfiguration.java
index 62708eb..95319f9 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/CommonConfiguration.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/CommonConfiguration.java
@@ -22,6 +22,7 @@ import java.util.concurrent.ExecutorService;
 
 import org.apache.olingo.client.api.http.HttpClientFactory;
 import org.apache.olingo.client.api.http.HttpUriRequestFactory;
+import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.format.ODataFormat;
 
 /**
@@ -33,13 +34,13 @@ public interface CommonConfiguration {
    * Gets the configured default <tt>Accept</tt> header value format for a batch request.
    * @return configured default <tt>Accept</tt> header value for a batch request.
    */
-  String getDefaultBatchAcceptFormat();
+  ContentType getDefaultBatchAcceptFormat();
   
   /**
    * Set the default <tt>Accept</tt> header value format for a batch request.
    * @param contentType default <tt>Accept</tt> header value.
    */
-  void setDefaultBatchAcceptFormat(String contentType);
+  void setDefaultBatchAcceptFormat(ContentType contentType);
   
   /**
    * Gets the configured OData format for AtomPub exchanges. If this configuration parameter doesn't exist the
@@ -69,8 +70,8 @@ public interface CommonConfiguration {
    * Gets the configured OData value format. If this configuration parameter doesn't exist the TEXT format will be used
    * as default.
    *
-   * @return configured OData value format if specified; TEXT format otherwise.
-   * @see ODataFormat#TEXT
+   * @return configured OData value format if specified; TEXT_PLAIN format otherwise.
+   * @see ODataFormat#TEXT_PLAIN
    */
   ODataFormat getDefaultValueFormat();
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/client-core/src/main/java/org/apache/olingo/client/core/Configuration.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/Configuration.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/Configuration.java
index a67bc11..2dc1993 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/Configuration.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/Configuration.java
@@ -82,12 +82,12 @@ public class Configuration implements CommonConfiguration {
   }
 
   @Override
-  public String getDefaultBatchAcceptFormat() {
-    return getProperty(DEFAULT_BATCH_ACCEPT_FORMAT, ContentType.MULTIPART_MIXED).toString();
+  public ContentType getDefaultBatchAcceptFormat() {
+    return (ContentType) getProperty(DEFAULT_BATCH_ACCEPT_FORMAT, ContentType.MULTIPART_MIXED);
   }
 
   @Override
-  public void setDefaultBatchAcceptFormat(final String contentType) {
+  public void setDefaultBatchAcceptFormat(final ContentType contentType) {
     setProperty(DEFAULT_BATCH_ACCEPT_FORMAT, contentType);
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AbstractODataBasicRequest.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AbstractODataBasicRequest.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AbstractODataBasicRequest.java
index cfb1112..cb72202 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AbstractODataBasicRequest.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AbstractODataBasicRequest.java
@@ -57,7 +57,7 @@ public abstract class AbstractODataBasicRequest<T extends ODataResponse>
   @Override
   public void setFormat(final ODataFormat format) {
     if (format != null) {
-      final String formatString = format.toString(odataClient.getServiceVersion());
+      final String formatString = format.getContentType(odataClient.getServiceVersion()).toContentTypeString();
       setAccept(formatString);
       setContentType(formatString);
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AbstractODataRequest.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AbstractODataRequest.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AbstractODataRequest.java
index 6a8e8d7..58412fc 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AbstractODataRequest.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AbstractODataRequest.java
@@ -184,7 +184,9 @@ public abstract class AbstractODataRequest extends AbstractRequest implements OD
   @Override
   public String getAccept() {
     final String acceptHead = odataHeaders.getHeader(HeaderName.accept);
-    return StringUtils.isBlank(acceptHead) ? getDefaultFormat().toString(odataClient.getServiceVersion()) : acceptHead;
+    return StringUtils.isBlank(acceptHead) ?
+        getDefaultFormat().getContentType(odataClient.getServiceVersion()).toContentTypeString() :
+        acceptHead;
   }
 
   @Override
@@ -205,8 +207,9 @@ public abstract class AbstractODataRequest extends AbstractRequest implements OD
   @Override
   public String getContentType() {
     final String contentTypeHead = odataHeaders.getHeader(HeaderName.contentType);
-    return StringUtils.isBlank(contentTypeHead)
-            ? getDefaultFormat().toString(odataClient.getServiceVersion()) : contentTypeHead;
+    return StringUtils.isBlank(contentTypeHead) ?
+        getDefaultFormat().getContentType(odataClient.getServiceVersion()).toContentTypeString() :
+        contentTypeHead;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/ODataBatchUtilities.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/ODataBatchUtilities.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/ODataBatchUtilities.java
index da46d82..b0429ac 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/ODataBatchUtilities.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/ODataBatchUtilities.java
@@ -95,7 +95,7 @@ public class ODataBatchUtilities {
    * <p>
    * Usually used to read an entire batch part.
    *
-   * @param batchController batch controller.
+   * @param controller batch controller.
    * @param os destination stream of batch part (null to discard).
    * @param checkCurrent if 'TRUE' the current line will be included into the delimiter verification.
    * @return latest read line.
@@ -111,7 +111,7 @@ public class ODataBatchUtilities {
    * <p>
    * Usually used to read an entire batch part.
    *
-   * @param batchController batch controller.
+   * @param controller batch controller.
    * @param os destination stream of batch part (null to discard).
    * @param count number of batch line to be read.
    * @param checkCurrent if 'TRUE' the current line will be included into the delimiter verification.
@@ -302,7 +302,7 @@ public class ODataBatchUtilities {
     final String contentType = headers.containsKey(HeaderName.contentType.toString())
             ? headers.get(HeaderName.contentType.toString()).toString() : StringUtils.EMPTY;
 
-    if (contentType.contains(ContentType.MULTIPART_MIXED)) {
+    if (contentType.contains(ContentType.MULTIPART_MIXED.toContentTypeString())) {
       nextItemType = BatchItemType.CHANGESET;
     } else if (contentType.contains(ODataBatchConstants.ITEM_CONTENT_TYPE)) {
       nextItemType = BatchItemType.RETRIEVE;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/v3/ODataBatchRequestImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/v3/ODataBatchRequestImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/v3/ODataBatchRequestImpl.java
index 3fbfddb..93821da 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/v3/ODataBatchRequestImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/v3/ODataBatchRequestImpl.java
@@ -49,7 +49,7 @@ public class ODataBatchRequestImpl
 
   public ODataBatchRequestImpl(final ODataClient odataClient, final URI uri) {
     super(odataClient, uri);
-    setAccept(odataClient.getConfiguration().getDefaultBatchAcceptFormat());
+    setAccept(odataClient.getConfiguration().getDefaultBatchAcceptFormat().toContentTypeString());
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/v4/ODataBatchRequestImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/v4/ODataBatchRequestImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/v4/ODataBatchRequestImpl.java
index 0c43549..8fea8ce 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/v4/ODataBatchRequestImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/batch/v4/ODataBatchRequestImpl.java
@@ -48,7 +48,7 @@ public class ODataBatchRequestImpl
 
   public ODataBatchRequestImpl(final ODataClient odataClient, final URI uri) {
     super(odataClient, uri);
-    setAccept(odataClient.getConfiguration().getDefaultBatchAcceptFormat());
+    setAccept(odataClient.getConfiguration().getDefaultBatchAcceptFormat().toContentTypeString());
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/invoke/AbstractODataInvokeRequest.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/invoke/AbstractODataInvokeRequest.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/invoke/AbstractODataInvokeRequest.java
index 714dd5e..5546778 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/invoke/AbstractODataInvokeRequest.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/invoke/AbstractODataInvokeRequest.java
@@ -97,9 +97,9 @@ public abstract class AbstractODataInvokeRequest<T extends ODataInvokeResult>
   }
 
   private String getActualFormat(final ODataFormat format) {
-    return (CommonODataProperty.class.isAssignableFrom(reference) && format == ODataFormat.ATOM)
-            ? ODataFormat.XML.toString(odataClient.getServiceVersion())
-            : format.toString(odataClient.getServiceVersion());
+    return ((CommonODataProperty.class.isAssignableFrom(reference) && format == ODataFormat.ATOM)
+            ? ODataFormat.XML : format)
+            .getContentType(odataClient.getServiceVersion()).toContentTypeString();
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/streamed/AbstractODataStreamedEntityRequest.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/streamed/AbstractODataStreamedEntityRequest.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/streamed/AbstractODataStreamedEntityRequest.java
index edbe31e..506270a 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/streamed/AbstractODataStreamedEntityRequest.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/streamed/AbstractODataStreamedEntityRequest.java
@@ -50,7 +50,7 @@ public abstract class AbstractODataStreamedEntityRequest<V extends ODataResponse
           final URI uri) {
 
     super(odataClient, method, uri);
-    setAccept(getFormat().toString(odataClient.getServiceVersion()));
+    setAccept(getFormat().getContentType(odataClient.getServiceVersion()).toContentTypeString());
   }
 
   @Override
@@ -61,6 +61,6 @@ public abstract class AbstractODataStreamedEntityRequest<V extends ODataResponse
   @Override
   public final void setFormat(final ODataFormat format) {
     this.format = format;
-    setAccept(format.toString(odataClient.getServiceVersion()));
+    setAccept(format.getContentType(odataClient.getServiceVersion()).toContentTypeString());
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataLinkType.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataLinkType.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataLinkType.java
index 28727ea..c7662a3 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataLinkType.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataLinkType.java
@@ -30,11 +30,11 @@ public enum ODataLinkType {
   /**
    * Entity navigation link.
    */
-  ENTITY_NAVIGATION(ContentType.APPLICATION_ATOM_XML + ";type=entry"),
+  ENTITY_NAVIGATION(ContentType.APPLICATION_ATOM_XML_ENTRY),
   /**
    * Entity set navigation link.
    */
-  ENTITY_SET_NAVIGATION(ContentType.APPLICATION_ATOM_XML + ";type=feed"),
+  ENTITY_SET_NAVIGATION(ContentType.APPLICATION_ATOM_XML_FEED),
   /**
    * Association link.
    */
@@ -50,6 +50,10 @@ public enum ODataLinkType {
     this.type = type;
   }
 
+  private ODataLinkType(ContentType contentType) {
+    this(contentType.toContentTypeString());
+  }
+
   private ODataLinkType setType(final String type) {
     this.type = type;
     return this;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java
index c37131c..12a3152 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java
@@ -1,70 +1,705 @@
-/*
+/*******************************************************************************
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * 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
+ * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
- */
+ ******************************************************************************/
 package org.apache.olingo.commons.api.format;
 
-import java.util.EnumMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
 import java.util.Map;
-import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+/**
+ * Internally used {@link ContentType} for OData library.
+ *
+ * For more details on format and content of a {@link ContentType} see
+ * <em>Media Type</em> format as defined in
+ * <a href="http://www.ietf.org/rfc/rfc7231.txt">RFC 7231</a>, chapter 3.1.1.1.
+ * <pre>
+ * media-type = type "/" subtype *( OWS ";" OWS parameter )
+ * type = token
+ * subtype = token
+ * OWS = *( SP / HTAB )  ; optional whitespace
+ * </pre>
+ *
+ * Especially for <code>Accept</code> Header as defined in
+ * RFC 7231, chapter 5.3.2:
+ * <pre>
+ * Accept = #( media-range [ accept-params ] )
+ * media-range = ( "&#42;/&#42;"
+ *               / ( type "/" "&#42;" )
+ *               / ( type "/" subtype )
+ *               ) *( OWS ";" OWS parameter )
+ * accept-params  = weight *( accept-ext )
+ * accept-ext = OWS ";" OWS token [ "=" ( token / quoted-string ) ]
+ * weight = OWS ";" OWS "q=" qvalue
+ * qvalue = ( "0" [ "." 0*3DIGIT ] ) / ( "1" [ "." 0*3("0") ] )
+ * </pre>
+ *
+ * Once created a {@link ContentType} is <b>IMMUTABLE</b>.
+ */
+public class ContentType {
+
+  private static final Comparator<String> Q_PARAMETER_COMPARATOR = new Comparator<String>() {
+    @Override
+    public int compare(final String o1, final String o2) {
+      Float f1 = parseQParameterValue(o1);
+      Float f2 = parseQParameterValue(o2);
+      return f2.compareTo(f1);
+    }
+  };
+
+  private static final char WHITESPACE_CHAR = ' ';
+  private static final String PARAMETER_SEPARATOR = ";";
+  private static final String PARAMETER_KEY_VALUE_SEPARATOR = "=";
+  private static final String TYPE_SUBTYPE_SEPARATOR = "/";
+  private static final String MEDIA_TYPE_WILDCARD = "*";
+
+  public static final String PARAMETER_Q = "q";
+  public static final String PARAMETER_TYPE = "type";
+  public static final String PARAMETER_CHARSET = "charset";
+  public static final String CHARSET_UTF_8 = "UTF-8";
+
+  private static final Pattern Q_PARAMETER_VALUE_PATTERN = Pattern.compile("1|0|1\\.0{1,3}|0\\.\\d{1,3}");
+
+  public static final ContentType WILDCARD = create(MEDIA_TYPE_WILDCARD, MEDIA_TYPE_WILDCARD);
+
+  public static final ContentType APPLICATION_XHTML_XML = create("application", "xhtml+xml");
+  public static final ContentType APPLICATION_SVG_XML = create("application", "svg+xml");
+  public static final ContentType APPLICATION_FORM_URLENCODED = create("application", "x-www-form-urlencoded");
+  public static final ContentType MULTIPART_FORM_DATA = create("multipart", "form-data");
+  public static final ContentType TEXT_XML = create("text", "xml");
+  public static final ContentType TEXT_HTML = create("text", "html");
+
+  public static final ContentType APPLICATION_XML = create("application", "xml");
+  public static final ContentType APPLICATION_XML_CS_UTF_8 = create(APPLICATION_XML, PARAMETER_CHARSET,
+          CHARSET_UTF_8);
+  public static final ContentType APPLICATION_ATOM_XML = create("application", "atom+xml");
+  public static final ContentType APPLICATION_ATOM_XML_CS_UTF_8 = create(APPLICATION_ATOM_XML,
+          PARAMETER_CHARSET, CHARSET_UTF_8);
+  public static final ContentType APPLICATION_ATOM_XML_ENTRY = create(APPLICATION_ATOM_XML, PARAMETER_TYPE, "entry");
+  public static final ContentType APPLICATION_ATOM_XML_ENTRY_CS_UTF_8 = create(APPLICATION_ATOM_XML_ENTRY,
+          PARAMETER_CHARSET, CHARSET_UTF_8);
+  public static final ContentType APPLICATION_ATOM_XML_FEED = create(APPLICATION_ATOM_XML, PARAMETER_TYPE, "feed");
+  public static final ContentType APPLICATION_ATOM_XML_FEED_CS_UTF_8 = ContentType.create(APPLICATION_ATOM_XML_FEED,
+          PARAMETER_CHARSET, CHARSET_UTF_8);
+  public static final ContentType APPLICATION_ATOM_SVC = create("application", "atomsvc+xml");
+  public static final ContentType APPLICATION_ATOM_SVC_CS_UTF_8 = create(APPLICATION_ATOM_SVC,
+          PARAMETER_CHARSET, CHARSET_UTF_8);
+  public static final ContentType APPLICATION_JSON = create("application", "json");
+  public static final ContentType APPLICATION_JSON_CS_UTF_8 = create(APPLICATION_JSON,
+      PARAMETER_CHARSET, CHARSET_UTF_8);
+  public static final ContentType APPLICATION_OCTET_STREAM = create("application", "octet-stream");
+  public static final ContentType TEXT_PLAIN = create("text", "plain");
+  public static final ContentType TEXT_PLAIN_CS_UTF_8 = ContentType
+          .create(TEXT_PLAIN, PARAMETER_CHARSET, CHARSET_UTF_8);
+  public static final ContentType MULTIPART_MIXED = create("multipart", "mixed");
+
+  private final String type;
+  private final String subtype;
+  private final Map<String, String> parameters;
+
+  private ContentType(final String type) {
+    if (type == null) {
+      throw new IllegalArgumentException("Type parameter MUST NOT be null.");
+    }
+    this.type = validateType(type);
+    subtype = null;
+    parameters = Collections.emptyMap();
+  }
+
+  /**
+   * Creates a content type from type, subtype, and parameters.
+  * @param type
+  * @param subtype
+  * @param parameters
+  */
+  private ContentType(final String type, final String subtype, final Map<String, String> parameters) {
+    if ((type == null || MEDIA_TYPE_WILDCARD.equals(type)) && !MEDIA_TYPE_WILDCARD.equals(subtype)) {
+      throw new IllegalArgumentException("Illegal combination of WILDCARD type with NONE WILDCARD subtype.");
+    }
+    this.type = validateType(type);
+    this.subtype = validateType(subtype);
+
+    if (parameters == null) {
+      this.parameters = Collections.emptyMap();
+    } else {
+      this.parameters = new TreeMap<String, String>(new Comparator<String>() {
+        @Override
+        public int compare(final String o1, final String o2) {
+          return o1.compareToIgnoreCase(o2);
+        }
+      });
+      this.parameters.putAll(parameters);
+      this.parameters.remove(PARAMETER_Q);
+    }
+  }
 
-public abstract class ContentType {
+  private String validateType(final String type) {
+    if (type == null || type.isEmpty()) {
+      return MEDIA_TYPE_WILDCARD;
+    }
+    int len = type.length();
+    for (int i = 0; i < len; i++) {
+      if (type.charAt(i) == WHITESPACE_CHAR) {
+        throw new IllegalArgumentException("Illegal whitespace found for type '" + type + "'.");
+      }
+    }
+    return type;
+  }
 
-  public static final String APPLICATION_ATOM_XML = "application/atom+xml";
+  /**
+   * Validates if given <code>format</code> is parseable and can be used as input for {@link #create(String)} method.
+   * @param format to be validated string
+   * @return <code>true</code> if format is parseable otherwise <code>false</code>
+   */
+  public static boolean isParseable(final String format) {
+    try {
+      return ContentType.create(format) != null;
+    } catch (IllegalArgumentException e) {
+      return false;
+    }
+  }
 
-  public static final String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded";
+  /**
+   * Creates a content type from type and subtype.
+   * @param type
+   * @param subtype
+   * @return a new <code>ContentType</code> object
+   */
+  public static ContentType create(final String type, final String subtype) {
+    return new ContentType(type, subtype, null);
+  }
 
-  public static final String APPLICATION_JSON = "application/json";
+  /**
+   *
+   * @param contentType
+   * @param parameterKey
+   * @param parameterValue
+   * @return a new <code>ContentType</code> object
+   */
+  public static ContentType create(final ContentType contentType,
+      final String parameterKey, final String parameterValue) {
+    ContentType ct = new ContentType(contentType.type, contentType.subtype, contentType.parameters);
+    ct.parameters.put(parameterKey, parameterValue);
+    return ct;
+  }
 
-  public static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
+  /**
+   * Create a {@link ContentType} based on given input string (<code>format</code>).
+   * Supported format is <code>Media Type</code> format as defined in RFC 7231, chapter 3.1.1.1.
+   * @param format a string in format as defined in RFC 7231, chapter 3.1.1.1
+   * @return a new <code>ContentType</code> object
+   * @throws IllegalArgumentException if input string is not parseable
+   */
+  public static ContentType create(final String format) {
+    if (format == null) {
+      throw new IllegalArgumentException("Parameter format MUST NOT be NULL.");
+    }
 
-  public static final String MULTIPART_MIXED = "multipart/mixed";
+    // split 'types' and 'parameters'
+    String[] typesAndParameters = format.split(PARAMETER_SEPARATOR, 2);
+    String types = typesAndParameters[0];
+    String parameters = (typesAndParameters.length > 1 ? typesAndParameters[1] : null);
+    //
+    Map<String, String> parametersMap = parseParameters(parameters);
+    //
+    if (types.contains(TYPE_SUBTYPE_SEPARATOR)) {
+      String[] tokens = types.split(TYPE_SUBTYPE_SEPARATOR);
+      if (tokens.length == 2) {
+        if (tokens[0] == null || tokens[0].isEmpty()) {
+          throw new IllegalArgumentException("No type found in format '" + format + "'.");
+        } else if (tokens[1] == null || tokens[1].isEmpty()) {
+          throw new IllegalArgumentException("No subtype found in format '" + format + "'.");
+        } else {
+          return new ContentType(tokens[0], tokens[1], parametersMap);
+        }
+      } else {
+        throw new IllegalArgumentException("Too many '" + TYPE_SUBTYPE_SEPARATOR + "' in format '" + format + "'.");
+      }
+    } else if (MEDIA_TYPE_WILDCARD.equals(types)) {
+      return ContentType.WILDCARD;
+    } else {
+      throw new IllegalArgumentException("No separator '" + TYPE_SUBTYPE_SEPARATOR + "' was found in format '" + format
+              + "'.");
+    }
+  }
 
-  public static final String APPLICATION_SVG_XML = "application/svg+xml";
+  /**
+   * Create a list of {@link ContentType} based on given input strings (<code>contentTypes</code>).
+   *
+   * Supported format is <code>Media Type</code> format as defined in RFC 7231, chapter 3.1.1.1.
+   * If one of the given strings can not be parsed an exception is thrown (hence no list is returned with the parseable
+   * strings).
+   * @param contentTypeStrings a list of strings in format as defined in <code>RFC 2616 section 3.7</code>
+   * @return a list of new <code>ContentType</code> object
+   * @throws IllegalArgumentException if one of the given input string is not parseable this exceptions is thrown
+   */
+  public static List<ContentType> create(final List<String> contentTypeStrings) {
+    List<ContentType> contentTypes = new ArrayList<ContentType>(contentTypeStrings.size());
+    for (String contentTypeString : contentTypeStrings) {
+      contentTypes.add(create(contentTypeString));
+    }
+    return contentTypes;
+  }
 
-  public static final String APPLICATION_XHTML_XML = "application/xhtml+xml";
+  /**
+   * Parses the given input string (<code>format</code>) and returns created {@link ContentType} if input was valid or
+   * return <code>NULL</code> if input was not parseable.
+   *
+   * For the definition of the supported format see {@link #create(String)}.
+   *
+   * @param format a string in format as defined in RFC 7231, chapter 3.1.1.1
+   * @return a new <code>ContentType</code> object
+   */
+  public static ContentType parse(final String format) {
+    try {
+      return ContentType.create(format);
+    } catch (IllegalArgumentException e) {
+      return null;
+    }
+  }
 
-  public static final String APPLICATION_XML = "application/xml";
+  /**
+   * Sort given list (which must contains content-type formatted string) for their {@value #PARAMETER_Q} value
+   * as defined in RFC 7231, chapter 3.1.1.1, and RFC 7231, chapter 5.3.1.
+   *
+   * <b>Attention:</b> For invalid values a {@value #PARAMETER_Q} value from <code>-1</code> is used for sorting.
+   *
+   * @param toSort list which is sorted and hence re-arranged
+   */
+  public static void sortForQParameter(final List<String> toSort) {
+    Collections.sort(toSort, ContentType.Q_PARAMETER_COMPARATOR);
+  }
 
-  public static final String MULTIPART_FORM_DATA = "multipart/form-data";
+  /**
+   * Valid input are <code>;</code> separated <code>key=value</code> pairs
+   * without spaces between key and value.
+   * <b>Attention:</b> <code>q</code> parameter is validated but not added to result map
+   *
+   * <p>
+   * See RFC 7231:
+   * The type, subtype, and parameter name tokens are case-insensitive.
+   * Parameter values might or might not be case-sensitive, depending on
+   * the semantics of the parameter name.  The presence or absence of a
+   * parameter might be significant to the processing of a media-type,
+   * depending on its definition within the media type registry.
+   * </p>
+   *
+   * @param parameters
+   * @return Map with keys mapped to values
+   */
+  private static Map<String, String> parseParameters(final String parameters) {
+    Map<String, String> parameterMap = new HashMap<String, String>();
+    if (parameters != null) {
+      String[] splittedParameters = parameters.split(PARAMETER_SEPARATOR);
+      for (String parameter : splittedParameters) {
+        String[] keyValue = parameter.split(PARAMETER_KEY_VALUE_SEPARATOR);
+        String key = keyValue[0].trim().toLowerCase(Locale.ENGLISH);
+        String value = keyValue.length > 1 ? keyValue[1] : null;
+        if (value != null && Character.isWhitespace(value.charAt(0))) {
+          throw new IllegalArgumentException("Value of parameter '" + key + "' starts with whitespace ('" + parameters
+                  + "').");
+        }
+        if (PARAMETER_Q.equals(key.toLowerCase(Locale.ENGLISH))) {
+          // q parameter is only validated but not added
+          if (!Q_PARAMETER_VALUE_PATTERN.matcher(value).matches()) {
+            throw new IllegalArgumentException("Value of 'q' parameter is not valid (q='" + value + "').");
+          }
+        } else {
+          parameterMap.put(key, value);
+        }
+      }
+    }
+    return parameterMap;
+  }
 
-  public static final String TEXT_HTML = "text/html";
+  /**
+   * Parse value of {@value #PARAMETER_Q} <code>parameter</code> out of content type/parameters.
+   * If no {@value #PARAMETER_Q} <code>parameter</code> is in <code>content type/parameters</code> parameter found
+   * <code>1</code> is returned.
+   * If {@value #PARAMETER_Q} <code>parameter</code> is invalid <code>-1</code> is returned.
+   *
+   * @param contentType parameter which is parsed for {@value #PARAMETER_Q} <code>parameter</code> value
+   * @return value of {@value #PARAMETER_Q} <code>parameter</code> or <code>1</code> or <code>-1</code>
+   */
+  private static Float parseQParameterValue(final String contentType) {
+    if (contentType != null) {
+      String[] splittedParameters = contentType.split(PARAMETER_SEPARATOR);
+      for (String parameter : splittedParameters) {
+        String[] keyValue = parameter.split(PARAMETER_KEY_VALUE_SEPARATOR);
+        String key = keyValue[0].trim().toLowerCase(Locale.ENGLISH);
+        if (PARAMETER_Q.equalsIgnoreCase(key)) {
+          String value = keyValue.length > 1 ? keyValue[1] : null;
+          if (Q_PARAMETER_VALUE_PATTERN.matcher(value).matches()) {
+            return Float.valueOf(value);
+          }
+          return Float.valueOf(-1);
+        }
+      }
+    }
+    return Float.valueOf(1);
+  }
 
-  public static final String TEXT_PLAIN = "text/plain";
+  /**
+   * Check if parameter with key value is an allowed parameter.
+   * @param key
+   * @return
+   */
+  private static boolean isParameterAllowed(final String key) {
+    return key != null && !PARAMETER_Q.equals(key.toLowerCase(Locale.ENGLISH));
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public String getSubtype() {
+    return subtype;
+  }
+
+  /**
+   *
+   * @return parameters of this {@link ContentType} as unmodifiable map.
+   */
+  public Map<String, String> getParameters() {
+    return Collections.unmodifiableMap(parameters);
+  }
+
+  @Override
+  public int hashCode() {
+    return 1;
+  }
 
-  public static final String TEXT_XML = "text/xml";
+  /**
+   * {@link ContentType}s are equal
+   * <ul>
+   * <li>if <code>type</code>, <code>subtype</code> and all <code>parameters</code> have the same value.</li>
+   * <li>if <code>type</code> and/or <code>subtype</code> is set to "*" (in such a case the <code>parameters</code> are
+   * ignored).</li>
+   * </ul>
+   *
+   * @return <code>true</code> if both instances are equal (see definition above), otherwise <code>false</code>.
+   */
+  @Override
+  public boolean equals(final Object obj) {
+    // NULL validation is done in method 'isEqualWithoutParameters(obj)'
+    Boolean compatible = isEqualWithoutParameters(obj);
 
-  public static final String WILDCARD = "*/*";
+    if (compatible == null) {
+      ContentType other = (ContentType) obj;
 
-  public static final EnumMap<ODataServiceVersion, Map<String, String>> formatPerVersion =
-          new EnumMap<ODataServiceVersion, Map<String, String>>(ODataServiceVersion.class);
+      // parameter checks
+      if (parameters == null) {
+        if (other.parameters != null) {
+          return false;
+        }
+      } else if (parameters.size() == other.parameters.size()) {
+        Iterator<Entry<String, String>> entries = parameters.entrySet().iterator();
+        Iterator<Entry<String, String>> otherEntries = other.parameters.entrySet().iterator();
+        while (entries.hasNext()) {
+          Entry<String, String> e = entries.next();
+          Entry<String, String> oe = otherEntries.next();
+
+          if (!areEqual(e.getKey(), oe.getKey())) {
+            return false;
+          }
+          if (!areEqual(e.getValue(), oe.getValue())) {
+            return false;
+          }
+        }
+      } else {
+        return false;
+      }
+      return true;
+    } else {
+      // all tests run
+      return compatible.booleanValue();
+    }
+  }
+
+  /**
+   * {@link ContentType}s are <b>compatible</b>
+   * <ul>
+   * <li>if <code>type</code>, <code>subtype</code> have the same value.</li>
+   * <li>if <code>type</code> and/or <code>subtype</code> is set to "*"</li>
+   * </ul>
+   * The set <code>parameters</code> are <b>always</b> ignored (for compare with parameters see {@link #equals(Object)}
+   * ).
+   *
+   * @return <code>true</code> if both instances are equal (see definition above), otherwise <code>false</code>.
+   */
+  public boolean isCompatible(final ContentType obj) {
+    Boolean compatible = isEqualWithoutParameters(obj);
+    if (compatible == null) {
+      return true;
+    }
+    return compatible.booleanValue();
+  }
+
+  /**
+   * Check equal without parameters.
+   * It is possible that no decision about <code>equal/none equal</code> can be determined a <code>NULL</code> is
+   * returned.
+   *
+   * @param obj to checked object
+   * @return <code>true</code> if both instances are equal (see definition above), otherwise <code>false</code>
+   * or <code>NULL</code> if no decision about <code>equal/none equal</code> could be determined.
+   */
+  private Boolean isEqualWithoutParameters(final Object obj) {
+    // basic checks
+    if (this == obj) {
+      return true;
+    }
+    if (obj == null) {
+      return false;
+    }
+    if (getClass() != obj.getClass()) {
+      return false;
+    }
+
+    ContentType other = (ContentType) obj;
+
+    // subtype checks
+    if (subtype == null) {
+      if (other.subtype != null) {
+        return false;
+      }
+    } else if (!subtype.equals(other.subtype)) {
+      if (other.subtype == null) {
+        return false;
+      } else if (!subtype.equals(MEDIA_TYPE_WILDCARD) && !other.subtype.equals(MEDIA_TYPE_WILDCARD)) {
+        return false;
+      }
+    }
+
+    // type checks
+    if (type == null) {
+      if (other.type != null) {
+        return false;
+      }
+    } else if (!type.equals(other.type)) {
+      if (!type.equals(MEDIA_TYPE_WILDCARD) && !other.type.equals(MEDIA_TYPE_WILDCARD)) {
+        return false;
+      }
+    }
+
+    // if wildcards are set, content types are defined as 'equal'
+    if (countWildcards() > 0 || other.countWildcards() > 0) {
+      return true;
+    }
+
+    return null;
+  }
+
+  /**
+   * Check whether both string are equal ignoring the case of the strings.
+   *
+   * @param first first string
+   * @param second second string
+   * @return <code>true</code> if both strings are equal (by ignoring the case), otherwise <code>false</code> is
+   * returned
+   */
+  private static boolean areEqual(final String first, final String second) {
+    if (first == null) {
+      if (second != null) {
+        return false;
+      }
+    } else if (!first.equalsIgnoreCase(second)) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Get {@link ContentType} as string as defined in RFC 7231 (http://www.ietf.org/rfc/rfc7231.txt, chapter 3.1.1.1:
+   * Media Type)
+   * @return string representation of <code>ContentType</code> object
+   */
+  public String toContentTypeString() {
+    StringBuilder sb = new StringBuilder();
+
+    sb.append(type).append(TYPE_SUBTYPE_SEPARATOR).append(subtype);
+
+    for (String key : parameters.keySet()) {
+      if (isParameterAllowed(key)) {
+        String value = parameters.get(key);
+        sb.append(";").append(key).append("=").append(value);
+      }
+    }
+    return sb.toString();
+  }
+
+  @Override
+  public String toString() {
+    return toContentTypeString();
+  }
+
+  /**
+   * Find best match between this {@link ContentType} and the {@link ContentType} in the list.
+   * If a match (this {@link ContentType} is equal to a {@link ContentType} in list) is found either this or the
+   * {@link ContentType} from the list is returned based on which {@link ContentType} has less "**" characters set
+   * (checked with {@link #compareWildcardCounts(ContentType)}.
+   * If no match (none {@link ContentType} in list is equal to this {@link ContentType}) is found <code>NULL</code> is
+   * returned.
+   *
+   * @param toMatchContentTypes list of {@link ContentType}s which are matches against this {@link ContentType}
+   * @return best matched content type in list or <code>NULL</code> if none content type match to this content type
+   * instance
+   */
+  public ContentType match(final List<ContentType> toMatchContentTypes) {
+    for (ContentType supportedContentType : toMatchContentTypes) {
+      if (equals(supportedContentType)) {
+        if (compareWildcardCounts(supportedContentType) < 0) {
+          return this;
+        } else {
+          return supportedContentType;
+        }
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Find best match between this {@link ContentType} and the {@link ContentType} in the list ignoring all set
+   * parameters.
+   * If a match (this {@link ContentType} is equal to a {@link ContentType} in list) is found either this or the
+   * {@link ContentType} from the list is returned based on which {@link ContentType} has less "**" characters set
+   * (checked with {@link #compareWildcardCounts(ContentType)}.
+   * If no match (none {@link ContentType} in list is equal to this {@link ContentType}) is found <code>NULL</code> is
+   * returned.
+   *
+   * @param toMatchContentTypes list of {@link ContentType}s which are matches against this {@link ContentType}
+   * @return best matched content type in list or <code>NULL</code> if none content type match to this content type
+   * instance
+   */
+  public ContentType matchCompatible(final List<ContentType> toMatchContentTypes) {
+    for (ContentType supportedContentType : toMatchContentTypes) {
+      if (isCompatible(supportedContentType)) {
+        if (compareWildcardCounts(supportedContentType) < 0) {
+          return this;
+        } else {
+          return supportedContentType;
+        }
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Check if a valid compatible match for this {@link ContentType} exists in given list.
+   * Compatible in this case means that <b>all set parameters are ignored</b>.
+   * For more detail what a valid match is see {@link #matchCompatible(List)}.
+   *
+   * @param toMatchContentTypes list of {@link ContentType}s which are matches against this {@link ContentType}
+   * @return <code>true</code> if a compatible content type was found in given list
+   * or <code>false</code> if none compatible content type match was found
+   */
+  public boolean hasCompatible(final List<ContentType> toMatchContentTypes) {
+    return matchCompatible(toMatchContentTypes) != null;
+  }
+
+  /**
+   * Check if a valid match for this {@link ContentType} exists in given list.
+   * For more detail what a valid match is see {@link #match(List)}.
+   *
+   * @param toMatchContentTypes list of {@link ContentType}s which are matches against this {@link ContentType}
+   * @return <code>true</code> if a matching content type was found in given list
+   * or <code>false</code> if none matching content type match was found
+   */
+  public boolean hasMatch(final List<ContentType> toMatchContentTypes) {
+    return match(toMatchContentTypes) != null;
+  }
+
+  /**
+   * Compare wildcards counts/weights of both {@link ContentType}.
+   *
+   * The smaller {@link ContentType} has lesser weighted wildcards then the bigger {@link ContentType}.
+   * As result this method returns this object weighted wildcards minus the given parameter object weighted wildcards.
+   *
+   * A type wildcard is weighted with <code>2</code> and a subtype wildcard is weighted with <code>1</code>.
+   *
+   * @param otherContentType {@link ContentType} to be compared to
+   * @return this object weighted wildcards minus the given parameter object weighted wildcards.
+   */
+  public int compareWildcardCounts(final ContentType otherContentType) {
+    return countWildcards() - otherContentType.countWildcards();
+  }
+
+  private int countWildcards() {
+    int count = 0;
+    if (MEDIA_TYPE_WILDCARD.equals(type)) {
+      count += 2;
+    }
+    if (MEDIA_TYPE_WILDCARD.equals(subtype)) {
+      count++;
+    }
+    return count;
+  }
+
+  /**
+   *
+   * @return <code>true</code> if <code>type</code> or <code>subtype</code> of this instance is a "*".
+   */
+  public boolean hasWildcard() {
+    return (MEDIA_TYPE_WILDCARD.equals(type) || MEDIA_TYPE_WILDCARD.equals(subtype));
+  }
+
+  /**
+   *
+   * @return <code>true</code> if both <code>type</code> and <code>subtype</code> of this instance are a "*".
+   */
+  public boolean isWildcard() {
+    return (MEDIA_TYPE_WILDCARD.equals(type) && MEDIA_TYPE_WILDCARD.equals(subtype));
+  }
+
+  public static List<ContentType> convert(final List<String> types) {
+    List<ContentType> results = new ArrayList<ContentType>();
+    for (String contentType : types) {
+      results.add(ContentType.create(contentType));
+    }
+    return results;
+  }
 
-  static {
-    final Map<String, String> v3 = new HashMap<String, String>();
-    v3.put(ODataFormat.JSON_NO_METADATA.name(), ContentType.APPLICATION_JSON + ";odata=nometadata");
-    v3.put(ODataFormat.JSON.name(), ContentType.APPLICATION_JSON + ";odata=minimalmetadata");
-    v3.put(ODataFormat.JSON_FULL_METADATA.name(), ContentType.APPLICATION_JSON + ";odata=fullmetadata");
-    formatPerVersion.put(ODataServiceVersion.V30, v3);
+  /**
+   * Check if a valid match for given content type formated string (<code>toMatch</code>) exists in given list.
+   * Therefore the given content type formated string (<code>toMatch</code>) is converted into a {@link ContentType}
+   * with a simple {@link #create(String)} call (during which an exception can occur).
+   *
+   * For more detail in general see {@link #hasMatch(List)} and for what a valid match is see {@link #match(List)}.
+   *
+   * @param toMatch content type formated string (<code>toMatch</code>) for which is checked if a match exists in given
+   * list
+   * @param matchExamples list of {@link ContentType}s which are matches against content type formated string
+   * (<code>toMatch</code>)
+   * @return <code>true</code> if a matching content type was found in given list
+   * or <code>false</code> if none matching content type match was found
+   */
+  public static boolean match(final String toMatch, final ContentType... matchExamples) {
+    ContentType toMatchContentType = ContentType.create(toMatch);
 
-    final Map<String, String> v4 = new HashMap<String, String>();
-    v4.put(ODataFormat.JSON_NO_METADATA.name(), ContentType.APPLICATION_JSON + ";odata.metadata=none");
-    v4.put(ODataFormat.JSON.name(), ContentType.APPLICATION_JSON + ";odata.metadata=minimal");
-    v4.put(ODataFormat.JSON_FULL_METADATA.name(), ContentType.APPLICATION_JSON + ";odata.metadata=full");
-    formatPerVersion.put(ODataServiceVersion.V40, v4);
+    return toMatchContentType.hasMatch(Arrays.asList(matchExamples));
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ODataFormat.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ODataFormat.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ODataFormat.java
index 37d0731..bc122e2 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ODataFormat.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ODataFormat.java
@@ -20,6 +20,9 @@ package org.apache.olingo.commons.api.format;
 
 import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Available formats to be used in various contexts.
  */
@@ -38,8 +41,6 @@ public enum ODataFormat {
   ATOM(ContentType.APPLICATION_ATOM_XML),
 
   // media formats
-  MEDIA_TYPE_WILDCARD("*"),
-  WILDCARD(ContentType.WILDCARD),
   APPLICATION_XML(ContentType.APPLICATION_XML),
   APPLICATION_ATOM_XML(ContentType.APPLICATION_ATOM_XML),
   APPLICATION_XHTML_XML(ContentType.APPLICATION_XHTML_XML),
@@ -52,79 +53,127 @@ public enum ODataFormat {
   TEXT_XML(ContentType.TEXT_XML),
   TEXT_HTML(ContentType.TEXT_HTML);
 
-  private final String format;
+  private static final String JSON_METADATA_PARAMETER_V3 = "odata";
+  private static final String JSON_METADATA_PARAMETER_V4 = "odata.metadata";
+
+  private static final Map<ODataServiceVersion, Map<ODataFormat, ContentType>> FORMAT_PER_VERSION = new
+      HashMap<ODataServiceVersion, Map<ODataFormat, ContentType>>();
+
+  static {
+    final Map<ODataFormat, ContentType> v3 = new HashMap<ODataFormat, ContentType>();
+    v3.put(ODataFormat.JSON_NO_METADATA, ContentType.create(
+        ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V3, "nometadata"));
+    v3.put(ODataFormat.JSON, ContentType.create(
+        ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V3, "minimalmetadata"));
+    v3.put(ODataFormat.JSON_FULL_METADATA, ContentType.create(
+        ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V3, "fullmetadata"));
+    FORMAT_PER_VERSION.put(ODataServiceVersion.V30, v3);
+
+    final Map<ODataFormat, ContentType> v4 = new HashMap<ODataFormat, ContentType>();
+    v4.put(ODataFormat.JSON_NO_METADATA, ContentType.create(
+        ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V4, "none"));
+    v4.put(ODataFormat.JSON, ContentType.create(
+        ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V4, "minimal"));
+    v4.put(ODataFormat.JSON_FULL_METADATA, ContentType.create(
+        ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V4, "full"));
+    FORMAT_PER_VERSION.put(ODataServiceVersion.V40, v4);
+  }
+
+  private final ContentType contentType;
 
-  ODataFormat() {
-    this.format = null;
+  ODataFormat(final ContentType contentType) {
+    this.contentType = contentType;
   }
 
-  ODataFormat(final String format) {
-    this.format = format;
+  ODataFormat() {
+    this.contentType = null;
   }
 
   /**
-   * Gets format as a string.
-   *
+   * Gets format as {@link ContentType}.
    * @param version OData service version.
-   * @return format as a string.
+   * @return format as ContentType.
    */
-  public String toString(final ODataServiceVersion version) {
+  public ContentType getContentType(final ODataServiceVersion version) {
     if (version.ordinal() < ODataServiceVersion.V30.ordinal()) {
       throw new IllegalArgumentException("Unsupported version " + version);
     }
 
-    return format == null ? ContentType.formatPerVersion.get(version).get(this.name()) : format;
+    return contentType == null ? FORMAT_PER_VERSION.get(version).get(this) : contentType;
   }
 
   @Override
   public String toString() {
-    if (format == null) {
+    if (contentType == null) {
       throw new UnsupportedOperationException();
     } else {
-      return format;
+      return contentType.toContentTypeString();
     }
   }
 
   /**
-   * Gets OData format from its string representation.
+   * Gets OData format from a content type.
    *
-   * @param format string representation of the format.
+   * @param contentType content type
    * @return OData format.
    */
-  public static ODataFormat fromString(final String format) {
-    ODataFormat result = null;
-
-    final StringBuffer _format = new StringBuffer();
-
-    final String[] parts = format.split(";");
-    _format.append(parts[0].trim());
-    if (ContentType.APPLICATION_JSON.equals(parts[0].trim())) {
-      if (parts.length > 1) {
-        if (parts[1].trim().equalsIgnoreCase("charset=UTF-8")) {
-          result = ODataFormat.JSON;
-        } else {
-          _format.append(';').append(parts[1].trim());
-        }
-      } else {
-        result = ODataFormat.JSON;
-      }
+  public static ODataFormat fromContentType(final ContentType contentType) {
+    if (contentType == null) {
+      return null;
+    }
+    if (contentType.hasWildcard()) {
+      throw new IllegalArgumentException("Content Type must be fully specified!");
     }
 
-    if (result == null) {
-      final String candidate = _format.toString();
-      for (ODataFormat value : values()) {
-        if (candidate.equals(value.toString(ODataServiceVersion.V30))
-                || candidate.equals(value.toString(ODataServiceVersion.V40))) {
-          result = value;
-          break;
+    if (contentType.isCompatible(ContentType.APPLICATION_ATOM_XML)
+        || contentType.isCompatible(ContentType.APPLICATION_ATOM_SVC)) {
+      return ATOM;
+    } else if (contentType.isCompatible(ContentType.APPLICATION_XML)) {
+      return XML;
+    } else if (contentType.isCompatible(ContentType.APPLICATION_JSON)) {
+      String jsonVariant = contentType.getParameters().get(JSON_METADATA_PARAMETER_V3);
+      if (jsonVariant != null) {
+        for (ODataFormat candidate : FORMAT_PER_VERSION.get(ODataServiceVersion.V30).keySet()) {
+          if (FORMAT_PER_VERSION.get(ODataServiceVersion.V30).get(candidate).getParameters()
+              .get(JSON_METADATA_PARAMETER_V3)
+              .equals(jsonVariant)) {
+            return candidate;
+          }
+        }
+      }
+      jsonVariant = contentType.getParameters().get(JSON_METADATA_PARAMETER_V4);
+      if (jsonVariant != null) {
+        for (ODataFormat candidate : FORMAT_PER_VERSION.get(ODataServiceVersion.V40).keySet()) {
+          if (FORMAT_PER_VERSION.get(ODataServiceVersion.V40).get(candidate).getParameters()
+              .get(JSON_METADATA_PARAMETER_V4)
+              .equals(jsonVariant)) {
+            return candidate;
+          }
         }
       }
+      return JSON;
+    } else if (contentType.isCompatible(ContentType.APPLICATION_OCTET_STREAM)) {
+      return APPLICATION_OCTET_STREAM;
+    } else if (contentType.isCompatible(ContentType.TEXT_PLAIN)) {
+      return TEXT_PLAIN;
+    } else if (contentType.isCompatible(ContentType.APPLICATION_XHTML_XML)) {
+      return APPLICATION_XHTML_XML;
+    } else if (contentType.isCompatible(ContentType.APPLICATION_SVG_XML)) {
+      return APPLICATION_SVG_XML;
+    } else if (contentType.isCompatible(ContentType.APPLICATION_FORM_URLENCODED)) {
+      return APPLICATION_FORM_URLENCODED;
+    } else if (contentType.isCompatible(ContentType.MULTIPART_FORM_DATA)) {
+      return MULTIPART_FORM_DATA;
+    } else if (contentType.isCompatible(ContentType.TEXT_XML)) {
+      return TEXT_XML;
+    } else if (contentType.isCompatible(ContentType.TEXT_HTML)) {
+      return TEXT_HTML;
     }
 
-    if (result == null) {
-      throw new IllegalArgumentException("Unsupported format: " + format);
-    }
+    throw new IllegalArgumentException("Unsupported content Type: " + contentType);
+  }
 
-    return result;
+  public static ODataFormat fromString(final String contentType) {
+    return contentType == null ? null : fromContentType(ContentType.parse(contentType));
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java
index fb2a041..74a76ad 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java
@@ -319,7 +319,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
       writer.writeStartElement(version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.PROPERTIES);
       properties(writer, entity.getProperties());
     } else {
-      writer.writeAttribute(Constants.ATTR_TYPE, ContentType.APPLICATION_XML);
+      writer.writeAttribute(Constants.ATTR_TYPE, ContentType.APPLICATION_XML.toContentTypeString());
       writer.writeStartElement(version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.PROPERTIES);
       properties(writer, entity.getProperties());
       writer.writeEndElement();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ab6fd5e2/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java
index 7e56c55..5c6c636 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java
@@ -72,7 +72,7 @@ public class SampleJsonProcessor implements EntitySetProcessor, EntityProcessor
       LOG.info("Finished in " + (System.nanoTime() - time) / 1000 + " microseconds");
 
       response.setStatusCode(200);
-      response.setHeader("Content-Type", ContentType.APPLICATION_JSON);
+      response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toContentTypeString());
     }
 
     @Override
@@ -91,7 +91,7 @@ public class SampleJsonProcessor implements EntitySetProcessor, EntityProcessor
       LOG.info("Finished in " + (System.nanoTime() - time) / 1000 + " microseconds");
 
       response.setStatusCode(200);
-      response.setHeader("Content-Type", ContentType.APPLICATION_JSON);
+      response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toContentTypeString());
     }
 
     protected Entity createEntity() {