From 210cf9b37d2d97848bb3ee4b27c60d33167021da Mon Sep 17 00:00:00 2001 From: Michael Bolz Date: Fri, 11 Jul 2014 10:51:37 +0200 Subject: [PATCH] [OLINGO-317] Support for JSON variants in server serializer --- .../olingo/server/core/ContentNegotiator.java | 17 +++-- .../apache/olingo/server/core/ODataImpl.java | 4 +- .../serializer/json/ODataJsonSerializer.java | 65 ++++++++++--------- .../tecsvc/processor/TechnicalProcessor.java | 4 +- .../tecsvc/data/JsonDataProviderTest.java | 7 +- .../json/ODataJsonSerializerTest.java | 48 +++++++++----- 6 files changed, 82 insertions(+), 63 deletions(-) diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java index ae932c352..793af7bf6 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java @@ -22,8 +22,10 @@ import java.util.ArrayList; import java.util.List; import org.apache.olingo.commons.api.ODataRuntimeException; +import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; import org.apache.olingo.commons.api.format.AcceptType; import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.server.api.ODataRequest; import org.apache.olingo.server.api.processor.CustomContentTypeSupportProcessor; @@ -34,8 +36,6 @@ import org.apache.olingo.server.api.uri.queryoption.FormatOption; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.dataformat.xml.util.TypeUtil; - public class ContentNegotiator { private final static Logger LOG = LoggerFactory.getLogger(ContentNegotiator.class); @@ -49,9 +49,8 @@ public class ContentNegotiator { if (processorClass == MetadataProcessor.class) { defaults.add(new FormatContentTypeMapping("xml", ContentType.APPLICATION_XML.toContentTypeString())); } else { -// defaults.add(new FormatContentTypeMapping("json", ContentType.APPLICATION_JSON.toContentTypeString())); - defaults.add(new FormatContentTypeMapping("json", ContentType.APPLICATION_JSON.toContentTypeString() - + ";odata.metadata=minimal")); + defaults.add(new FormatContentTypeMapping("json", + ODataFormat.JSON.getContentType(ODataServiceVersion.V40).toContentTypeString())); } return defaults; @@ -84,7 +83,7 @@ public class ContentNegotiator { if (formatOption != null) { if ("json".equalsIgnoreCase(formatOption.getText().trim())) { - requestedContentType = ContentType.create(ContentType.APPLICATION_JSON, "odata.metadata=minimal"); + requestedContentType = ODataFormat.JSON.getContentType(ODataServiceVersion.V40); for (FormatContentTypeMapping entry : supportedContentTypes) { if (requestedContentType.isCompatible(ContentType.create(entry.getContentType().trim()))) { supported = true; @@ -136,7 +135,7 @@ public class ContentNegotiator { } if (requestedContentType == null) { - throw new RuntimeException("unsupported accept content type: " + acceptedContentTypes + " != " + throw new ODataRuntimeException("unsupported accept content type: " + acceptedContentTypes + " != " + supportedContentTypes); } } else { @@ -144,7 +143,7 @@ public class ContentNegotiator { if (processorClass == MetadataProcessor.class) { requestedContentType = ContentType.APPLICATION_XML; } else { - requestedContentType = ContentType.create(ContentType.APPLICATION_JSON, "odata.metadata=minimal"); + requestedContentType = ODataFormat.JSON.getContentType(ODataServiceVersion.V40); } for (FormatContentTypeMapping entry : supportedContentTypes) { @@ -156,7 +155,7 @@ public class ContentNegotiator { } if (!supported) { - throw new RuntimeException("unsupported accept content type: " + requestedContentType + " != " + throw new ODataRuntimeException("unsupported accept content type: " + requestedContentType + " != " + supportedContentTypes); } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java index 1d1fdaf86..c3eb43e02 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java @@ -36,7 +36,9 @@ public class ODataImpl extends OData { ODataSerializer serializer; switch (format) { case JSON: - serializer = new ODataJsonSerializer(); + case JSON_NO_METADATA: + case JSON_FULL_METADATA: + serializer = new ODataJsonSerializer(format); break; case XML: serializer = new ODataXmlSerializerImpl(); 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 4870a5cef..b2025eb5b 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 @@ -40,6 +40,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveType; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.EdmProperty; +import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer; @@ -54,6 +55,12 @@ public class ODataJsonSerializer implements ODataSerializer { private static final Logger log = LoggerFactory.getLogger(ODataJsonSerializer.class); + private final ODataFormat format; + + public ODataJsonSerializer(final ODataFormat format) { + this.format = format; + } + @Override public InputStream serviceDocument(final Edm edm, final String serviceRoot) { CircleStreamBuffer buffer; @@ -100,6 +107,19 @@ public class ODataJsonSerializer implements ODataSerializer { throw new ODataRuntimeException("Metadata in JSON format not supported!"); } + @Override + public InputStream error(final ODataError error) { + CircleStreamBuffer buffer = new CircleStreamBuffer(); + try { + JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); + new ODataErrorSerializer().writeErrorDocument(json, error); + json.close(); + } catch (final IOException e) { + throw new ODataRuntimeException(e); + } + return buffer.getInputStream(); + } + @Override public InputStream entitySet(final EdmEntitySet edmEntitySet, final EntitySet entitySet, final ContextURL contextURL) { @@ -107,7 +127,7 @@ public class ODataJsonSerializer implements ODataSerializer { try { JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); json.writeStartObject(); - if (contextURL != null) { + if (contextURL != null && format != ODataFormat.JSON_NO_METADATA) { json.writeStringField(Constants.JSON_CONTEXT, contextURL.getURI().toASCIIString()); } if (entitySet.getCount() != null) { @@ -149,17 +169,19 @@ public class ODataJsonSerializer implements ODataSerializer { protected void writeEntity(final EdmEntityType entityType, final Entity entity, final ContextURL contextURL, final JsonGenerator json) throws IOException, EdmPrimitiveTypeException { json.writeStartObject(); - if (contextURL != null) { - json.writeStringField(Constants.JSON_CONTEXT, contextURL.getURI().toASCIIString()); - } - if (entity.getETag() != null) { - json.writeStringField("@odata.etag", entity.getETag()); - } - if (entity.getMediaETag() != null) { - json.writeStringField("@odata.mediaEtag", entity.getMediaETag()); - } - if (entity.getMediaContentType() != null) { - json.writeStringField("@odata.mediaContentType", entity.getMediaContentType()); + if (format != ODataFormat.JSON_NO_METADATA) { + if (contextURL != null) { + json.writeStringField(Constants.JSON_CONTEXT, contextURL.getURI().toASCIIString()); + } + if (entity.getETag() != null) { + json.writeStringField("@odata.etag", entity.getETag()); + } + if (entity.getMediaETag() != null) { + json.writeStringField("@odata.mediaEtag", entity.getMediaETag()); + } + if (entity.getMediaContentType() != null) { + json.writeStringField("@odata.mediaContentType", entity.getMediaContentType()); + } } for (final String propertyName : entityType.getPropertyNames()) { final EdmProperty edmProperty = (EdmProperty) entityType.getProperty(propertyName); @@ -185,7 +207,7 @@ public class ODataJsonSerializer implements ODataSerializer { writePrimitive(edmProperty, property, json); } else if (property.isLinkedComplex()) { writeComplexValue(edmProperty, property.asLinkedComplex().getValue(), json); - } else if (property.isComplex()) { + } else if(property.isComplex()) { writeComplexValue(edmProperty, property.asComplex(), json); } else { throw new ODataRuntimeException("Property type not yet supported!"); @@ -193,7 +215,6 @@ public class ODataJsonSerializer implements ODataSerializer { } } - private void writeCollection(EdmProperty edmProperty, Property property, JsonGenerator json) throws IOException, EdmPrimitiveTypeException { json.writeStartArray(); @@ -257,7 +278,7 @@ public class ODataJsonSerializer implements ODataSerializer { } private void writeComplexValue(final EdmProperty edmProperty, final List properties, - JsonGenerator json) throws IOException, EdmPrimitiveTypeException { + JsonGenerator json) throws IOException, EdmPrimitiveTypeException { final EdmComplexType type = (EdmComplexType) edmProperty.getType(); json.writeStartObject(); for (final String propertyName : type.getPropertyNames()) { @@ -275,18 +296,4 @@ public class ODataJsonSerializer implements ODataSerializer { } return null; } - - @Override - public InputStream error(ODataError error) { - CircleStreamBuffer buffer = new CircleStreamBuffer(); - try { - JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); - ODataErrorSerializer ser = new ODataErrorSerializer(); - ser.writeErrorDocument(json, error); - json.close(); - } catch (final IOException e) { - throw new ODataRuntimeException(e); - } - return buffer.getInputStream(); - } } 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 8e126b78b..f9d1e5584 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 @@ -66,7 +66,7 @@ public class TechnicalProcessor implements CollectionProcessor, EntityProcessor response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); return; } - ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON); + ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(requestedContentType)); final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource()); try { final EntitySet entitySet = readEntitySetInternal(edmEntitySet, request.getRawBaseUri()); @@ -90,7 +90,7 @@ public class TechnicalProcessor implements CollectionProcessor, EntityProcessor response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); return; } - ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON); + ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(requestedContentType)); final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource()); try { final Entity entity = readEntityInternal(uriInfo.asUriInfoResource(), edmEntitySet); diff --git a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java index cc8ddce35..462855c4e 100644 --- a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java +++ b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java @@ -35,6 +35,7 @@ import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmStructuredType; import org.apache.olingo.commons.api.edm.FullQualifiedName; +import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.core.serializer.json.ODataJsonSerializer; import org.apache.olingo.server.tecsvc.provider.ContainerProvider; @@ -184,16 +185,12 @@ public class JsonDataProviderTest { EntitySet outSet = jdp.readAll(entitySet); - ODataJsonSerializer serializer = new ODataJsonSerializer(); + ODataJsonSerializer serializer = new ODataJsonSerializer(ODataFormat.JSON); ContextURL contextUrl = null; InputStream is = serializer.entitySet(entitySet, outSet, contextUrl); StringHelper.Stream stream = StringHelper.toStream(is); -// System.out.println("========== " + entitySet.getName() + " ================="); -// stream.print(); -// System.out.println("\n========== " + entitySet.getName() + " ================="); - Assert.assertEquals(expectedLength, stream.asString().length()); } } 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 f1987fd8f..d3753b400 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 @@ -18,10 +18,10 @@ */ package org.apache.olingo.server.core.serializer.json; -import java.io.IOException; import java.io.InputStream; import java.net.URI; +import org.apache.commons.io.IOUtils; import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.EntitySet; @@ -29,6 +29,7 @@ import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.EdmEntityContainer; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.FullQualifiedName; +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.tecsvc.data.DataProvider; @@ -42,7 +43,7 @@ public class ODataJsonSerializerTest { private final EdmEntityContainer entityContainer = edm.getEntityContainer( new FullQualifiedName("com.sap.odata.test1", "Container")); private final DataProvider data = new DataProvider(edm); - private ODataSerializer serializer = new ODataJsonSerializer(); + private ODataSerializer serializer = new ODataJsonSerializer(ODataFormat.JSON); @Test public void entitySimple() throws Exception { @@ -50,7 +51,7 @@ public class ODataJsonSerializerTest { final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); InputStream result = serializer.entity(edmEntitySet.getEntityType(), entity, ContextURL.getInstance(URI.create("$metadata#ESAllPrim/$entity"))); - final String resultString = streamToString(result); + final String resultString = IOUtils.toString(result); final String expectedResult = "{" + "\"@odata.context\":\"$metadata#ESAllPrim/$entity\"," + "\"PropertyInt16\":32767," @@ -81,7 +82,7 @@ public class ODataJsonSerializerTest { entitySet.setNext(URI.create("/next")); InputStream result = serializer.entitySet(edmEntitySet, entitySet, ContextURL.getInstance(URI.create("$metadata#ESAllPrim"))); - final String resultString = streamToString(result); + final String resultString = IOUtils.toString(result); Assert.assertTrue(resultString.matches("\\{" + "\"@odata\\.context\":\"\\$metadata#ESAllPrim\"," @@ -104,7 +105,7 @@ public class ODataJsonSerializerTest { final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); InputStream result = serializer.entity(edmEntitySet.getEntityType(), entity, ContextURL.getInstance(URI.create("$metadata#ESCollAllPrim/$entity"))); - final String resultString = streamToString(result); + final String resultString = IOUtils.toString(result); final String expectedResult = "{" + "\"@odata.context\":\"$metadata#ESCollAllPrim/$entity\"," + "\"PropertyInt16\":1," @@ -136,7 +137,7 @@ public class ODataJsonSerializerTest { final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); InputStream result = serializer.entity(edmEntitySet.getEntityType(), entity, ContextURL.getInstance(URI.create("$metadata#ESCompAllPrim/$entity"))); - final String resultString = streamToString(result); + final String resultString = IOUtils.toString(result); final String expectedResult = "{" + "\"@odata.context\":\"$metadata#ESCompAllPrim/$entity\"," + "\"PropertyInt16\":32767," @@ -167,7 +168,7 @@ public class ODataJsonSerializerTest { final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); InputStream result = serializer.entity(edmEntitySet.getEntityType(), entity, ContextURL.getInstance(URI.create("$metadata#ESMixPrimCollComp/$entity"))); - final String resultString = streamToString(result); + final String resultString = IOUtils.toString(result); final String expectedResult = "{" + "\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\"," + "\"PropertyInt16\":32767," @@ -180,16 +181,29 @@ public class ODataJsonSerializerTest { Assert.assertEquals(expectedResult, resultString); } - private String streamToString(InputStream input) throws IOException { - byte[] buffer = new byte[8192]; - StringBuilder result = new StringBuilder(); + @Test + public void entityTwoPrimNoMetadata() throws Exception { + 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.getEntityType(), entity, ContextURL.getInstance(URI.create("contextURL"))); + final String resultString = IOUtils.toString(result); + final String expectedResult = "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}"; + Assert.assertEquals(expectedResult, resultString); + } - int count = input.read(buffer); - while (count >= 0) { - result.append(new String(buffer, 0, count, "UTF-8")); - count = input.read(buffer); - } - - return result.toString(); + @Test + public void entitySetTwoPrimNoMetadata() throws Exception { + final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESTwoPrim"); + final EntitySet entitySet = data.readAll(edmEntitySet); + InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) + .entitySet(edmEntitySet, entitySet, ContextURL.getInstance(URI.create("contextURL"))); + final String resultString = IOUtils.toString(result); + final String expectedResult = "{\"value\":[" + + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}," + + "{\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\"}," + + "{\"PropertyInt16\":-32766,\"PropertyString\":\"Test String3\"}," + + "{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"}]}"; + Assert.assertEquals(expectedResult, resultString); } }