diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java index 073dfd56c..a0d44b9ae 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java @@ -26,6 +26,7 @@ import org.apache.olingo.commons.api.data.EntitySet; import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.server.api.ODataServerError; +import org.apache.olingo.server.api.uri.queryoption.ExpandItem; public interface ODataSerializer { @@ -35,10 +36,10 @@ public interface ODataSerializer { InputStream metadataDocument(Edm edm) throws ODataSerializerException; - InputStream entity(EdmEntitySet edmEntitySet, Entity entity, ContextURL contextURL) + InputStream entity(EdmEntitySet edmEntitySet, Entity entity, ContextURL contextURL, ExpandItem options) throws ODataSerializerException; - InputStream entitySet(EdmEntitySet edmEntitySet, EntitySet entitySet, ContextURL contextURL) + InputStream entitySet(EdmEntitySet edmEntitySet, EntitySet entitySet, ContextURL contextURL, ExpandItem options) throws ODataSerializerException; /** diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java index 5aed27723..f3043c11a 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java @@ -32,6 +32,7 @@ import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializerException; +import org.apache.olingo.server.api.uri.queryoption.ExpandItem; import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer; import org.apache.olingo.server.core.serializer.xml.MetadataDocumentXmlSerializer; import org.slf4j.Logger; @@ -79,15 +80,15 @@ public class ODataXmlSerializerImpl implements ODataSerializer { } @Override - public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity, final ContextURL contextURL) - throws ODataSerializerException { + public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity, final ContextURL contextURL, + final ExpandItem options) throws ODataSerializerException { throw new ODataSerializerException("Entity serialization not implemented for XML format", ODataSerializerException.MessageKeys.NOT_IMPLEMENTED); } @Override public InputStream entitySet(final EdmEntitySet edmEntitySet, final EntitySet entitySet, - final ContextURL contextURL) throws ODataSerializerException { + final ContextURL contextURL, final ExpandItem options) throws ODataSerializerException { throw new ODataSerializerException("Entityset serialization not implemented for XML format", ODataSerializerException.MessageKeys.NOT_IMPLEMENTED); } 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 698267844..665c258e3 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 @@ -20,7 +20,10 @@ package org.apache.olingo.server.core.serializer.json; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.apache.olingo.commons.api.Constants; import org.apache.olingo.commons.api.data.ContextURL; @@ -41,6 +44,10 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializerException; +import org.apache.olingo.server.api.uri.UriResource; +import org.apache.olingo.server.api.uri.UriResourceProperty; +import org.apache.olingo.server.api.uri.queryoption.ExpandItem; +import org.apache.olingo.server.api.uri.queryoption.SelectItem; import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer; import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder; import org.slf4j.Logger; @@ -119,7 +126,7 @@ public class ODataJsonSerializer implements ODataSerializer { @Override public InputStream entitySet(final EdmEntitySet edmEntitySet, final EntitySet entitySet, - final ContextURL contextURL) throws ODataSerializerException { + final ContextURL contextURL, final ExpandItem options) throws ODataSerializerException { CircleStreamBuffer buffer = new CircleStreamBuffer(); try { JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); @@ -138,7 +145,7 @@ public class ODataJsonSerializer implements ODataSerializer { json.writeFieldName(Constants.VALUE); json.writeStartArray(); for (Entity entity : entitySet.getEntities()) { - writeEntity(edmEntitySet, entity, null, json); + writeEntity(edmEntitySet, entity, null, options, json); } json.writeEndArray(); if (entitySet.getNext() != null) { @@ -153,8 +160,8 @@ public class ODataJsonSerializer implements ODataSerializer { } @Override - public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity, final ContextURL contextURL) - throws ODataSerializerException { + public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity, final ContextURL contextURL, + final ExpandItem options) throws ODataSerializerException { if (format != ODataFormat.JSON_NO_METADATA && contextURL == null) { throw new ODataSerializerException("ContextURL null!", ODataSerializerException.MessageKeys.NO_CONTEXT_URL); @@ -162,7 +169,7 @@ public class ODataJsonSerializer implements ODataSerializer { CircleStreamBuffer buffer = new CircleStreamBuffer(); try { JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); - writeEntity(edmEntitySet, entity, contextURL, json); + writeEntity(edmEntitySet, entity, contextURL, options, json); json.close(); } catch (final IOException e) { throw new ODataSerializerException("An I/O exception occurred.", e, @@ -172,7 +179,7 @@ public class ODataJsonSerializer implements ODataSerializer { } protected void writeEntity(final EdmEntitySet entitySet, final Entity entity, final ContextURL contextURL, - final JsonGenerator json) throws IOException, ODataSerializerException { + final ExpandItem options, final JsonGenerator json) throws IOException, ODataSerializerException { final EdmEntityType entityType = entitySet.getEntityType(); json.writeStartObject(); if (format != ODataFormat.JSON_NO_METADATA) { @@ -191,16 +198,71 @@ public class ODataJsonSerializer implements ODataSerializer { } } } + final boolean all = isAll(options); + final Set selected = all ? null : getSelectedPropertyNames(options.getSelectOption().getSelectItems()); for (final String propertyName : entityType.getPropertyNames()) { - final EdmProperty edmProperty = (EdmProperty) entityType.getProperty(propertyName); - final Property property = entity.getProperty(propertyName); - writeProperty(edmProperty, property, json); + if (all || selected.contains(propertyName)) { + final EdmProperty edmProperty = (EdmProperty) entityType.getProperty(propertyName); + final Property property = entity.getProperty(propertyName); + final Set> selectedPaths = all || edmProperty.isPrimitive() ? null : + getSelectedPaths(options.getSelectOption().getSelectItems(), propertyName); + writeProperty(edmProperty, property, selectedPaths, json); + } } json.writeEndObject(); } - protected void writeProperty(final EdmProperty edmProperty, final Property property, final JsonGenerator json) - throws IOException, ODataSerializerException { + private boolean isAll(final ExpandItem options) { + if (options == null || options.getSelectOption() == null + || options.getSelectOption().getSelectItems() == null + || options.getSelectOption().getSelectItems().isEmpty()) { + return true; + } else { + for (final SelectItem item : options.getSelectOption().getSelectItems()) { + if (item.isStar()) { + return true; + } + } + return false; + } + } + + private Set getSelectedPropertyNames(final List selectItems) { + Set selected = new HashSet(); + for (final SelectItem item : selectItems) { + final UriResource resource = item.getResourcePath().getUriResourceParts().get(0); + if (resource instanceof UriResourceProperty) { + selected.add(((UriResourceProperty) resource).getProperty().getName()); + } + } + return selected; + } + + private Set> getSelectedPaths(final List selectItems, final String propertyName) { + Set> selectedPaths = new HashSet>(); + for (final SelectItem item : selectItems) { + final List parts = item.getResourcePath().getUriResourceParts(); + final UriResource resource = parts.get(0); + if (resource instanceof UriResourceProperty + && propertyName.equals(((UriResourceProperty) resource).getProperty().getName())) { + if (parts.size() > 1) { + List path = new ArrayList(); + for (final UriResource part : parts.subList(1, parts.size())) { + if (part instanceof UriResourceProperty) { + path.add(((UriResourceProperty) part).getProperty().getName()); + } + } + selectedPaths.add(path); + } else { + return null; + } + } + } + return selectedPaths.isEmpty() ? null : selectedPaths; + } + + protected void writeProperty(final EdmProperty edmProperty, final Property property, + final Set> selectedPaths, final JsonGenerator json) throws IOException, ODataSerializerException { json.writeFieldName(edmProperty.getName()); if (property == null || property.isNull()) { if (edmProperty.isNullable() == Boolean.FALSE) { @@ -212,13 +274,13 @@ public class ODataJsonSerializer implements ODataSerializer { } else { try { if (edmProperty.isCollection()) { - writeCollection(edmProperty, property, json); + writeCollection(edmProperty, property, selectedPaths, json); } else if (edmProperty.isPrimitive()) { writePrimitive(edmProperty, property, json); } else if (property.isLinkedComplex()) { - writeComplexValue(edmProperty, property.asLinkedComplex().getValue(), json); + writeComplexValue(edmProperty, property.asLinkedComplex().getValue(), selectedPaths, json); } else if (property.isComplex()) { - writeComplexValue(edmProperty, property.asComplex(), json); + writeComplexValue(edmProperty, property.asComplex(), selectedPaths, json); } else { throw new ODataSerializerException("Property type not yet supported!", ODataSerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, edmProperty.getName()); @@ -231,7 +293,8 @@ public class ODataJsonSerializer implements ODataSerializer { } } - private void writeCollection(EdmProperty edmProperty, Property property, JsonGenerator json) + private void writeCollection(final EdmProperty edmProperty, final Property property, + final Set> selectedPaths, JsonGenerator json) throws IOException, EdmPrimitiveTypeException, ODataSerializerException { json.writeStartArray(); for (Object value : property.asCollection()) { @@ -246,10 +309,10 @@ public class ODataJsonSerializer implements ODataSerializer { json.writeString(value.toString()); break; case COLLECTION_LINKED_COMPLEX: - writeComplexValue(edmProperty, ((LinkedComplexValue) value).getValue(), json); + writeComplexValue(edmProperty, ((LinkedComplexValue) value).getValue(), selectedPaths, json); break; case COLLECTION_COMPLEX: - writeComplexValue(edmProperty, property.asComplex(), json); + writeComplexValue(edmProperty, property.asComplex(), selectedPaths, json); break; default: throw new ODataSerializerException("Property type not yet supported!", @@ -298,12 +361,17 @@ public class ODataJsonSerializer implements ODataSerializer { } private void writeComplexValue(final EdmProperty edmProperty, final List properties, - JsonGenerator json) throws IOException, EdmPrimitiveTypeException, ODataSerializerException { + final Set> selectedPaths, JsonGenerator json) + throws IOException, EdmPrimitiveTypeException, ODataSerializerException { final EdmComplexType type = (EdmComplexType) edmProperty.getType(); json.writeStartObject(); for (final String propertyName : type.getPropertyNames()) { final Property property = findProperty(propertyName, properties); - writeProperty((EdmProperty) type.getProperty(propertyName), property, json); + if (selectedPaths == null || isSelected(selectedPaths, propertyName)) { + writeProperty((EdmProperty) type.getProperty(propertyName), property, + selectedPaths == null ? null : getReducedSelectedPaths(selectedPaths, propertyName), + json); + } } json.writeEndObject(); } @@ -316,4 +384,28 @@ public class ODataJsonSerializer implements ODataSerializer { } return null; } + + private boolean isSelected(final Set> selectedPaths, final String propertyName) { + for (final List path : selectedPaths) { + if (propertyName.equals(path.get(0))) { + return true; + } + } + return false; + } + + private Set> getReducedSelectedPaths(final Set> selectedPaths, + final String propertyName) { + Set> reducedPaths = new HashSet>(); + for (final List path : selectedPaths) { + if (path.size() > 1) { + if (propertyName.equals(path.get(0))) { + reducedPaths.add(path.subList(1, path.size())); + } + } else { + return null; + } + } + return reducedPaths.isEmpty() ? null : reducedPaths; + } } diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java index f6c9f3a22..c1b55c470 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java @@ -31,6 +31,7 @@ import java.util.UUID; import org.apache.olingo.commons.api.ODataException; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.EntitySet; +import org.apache.olingo.commons.api.data.Link; import org.apache.olingo.commons.api.data.LinkedComplexValue; import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.ValueType; @@ -41,6 +42,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.core.data.EntityImpl; import org.apache.olingo.commons.core.data.EntitySetImpl; +import org.apache.olingo.commons.core.data.LinkImpl; import org.apache.olingo.commons.core.data.LinkedComplexValueImpl; import org.apache.olingo.commons.core.data.PropertyImpl; import org.apache.olingo.server.api.uri.UriParameter; @@ -59,7 +61,11 @@ public class DataProvider { data.put("ESCollAllPrim", createESCollAllPrim()); data.put("ESMixPrimCollComp", createESMixPrimCollComp()); data.put("ESAllKey", createESAllKey()); + data.put("ESCompComp", createESCompComp()); data.put("ESMedia", createESMedia()); + + linkESTwoPrim(); + linkESAllPrim(); } public EntitySet readAll(final EdmEntitySet edmEntitySet) throws DataProviderException { @@ -112,25 +118,21 @@ public class DataProvider { private EntitySet createESTwoPrim() { EntitySet entitySet = new EntitySetImpl(); - Entity entity = new EntityImpl(); - entity.addProperty(createPrimitive("PropertyInt16", 32766)); - entity.addProperty(createPrimitive("PropertyString", "Test String1")); - entitySet.getEntities().add(entity); + entitySet.getEntities().add(new EntityImpl() + .addProperty(createPrimitive("PropertyInt16", 32766)) + .addProperty(createPrimitive("PropertyString", "Test String1"))); - entity = new EntityImpl(); - entity.addProperty(createPrimitive("PropertyInt16", -365)); - entity.addProperty(createPrimitive("PropertyString", "Test String2")); - entitySet.getEntities().add(entity); + entitySet.getEntities().add(new EntityImpl() + .addProperty(createPrimitive("PropertyInt16", -365)) + .addProperty(createPrimitive("PropertyString", "Test String2"))); - entity = new EntityImpl(); - entity.addProperty(createPrimitive("PropertyInt16", -32766)); - entity.addProperty(createPrimitive("PropertyString", "Test String3")); - entitySet.getEntities().add(entity); + entitySet.getEntities().add(new EntityImpl() + .addProperty(createPrimitive("PropertyInt16", -32766)) + .addProperty(createPrimitive("PropertyString", "Test String3"))); - entity = new EntityImpl(); - entity.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE)); - entity.addProperty(createPrimitive("PropertyString", "Test String4")); - entitySet.getEntities().add(entity); + entitySet.getEntities().add(new EntityImpl() + .addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE)) + .addProperty(createPrimitive("PropertyString", "Test String4"))); return entitySet; } @@ -138,64 +140,61 @@ public class DataProvider { private EntitySet createESAllPrim() { EntitySet entitySet = new EntitySetImpl(); - Entity entity = new EntityImpl(); - entity.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE)); - entity.addProperty(createPrimitive("PropertyString", "First Resource - positive values")); - entity.addProperty(createPrimitive("PropertyBoolean", true)); - entity.addProperty(createPrimitive("PropertyByte", 255)); - entity.addProperty(createPrimitive("PropertySByte", Byte.MAX_VALUE)); - entity.addProperty(createPrimitive("PropertyInt32", Integer.MAX_VALUE)); - entity.addProperty(createPrimitive("PropertyInt64", Long.MAX_VALUE)); - entity.addProperty(createPrimitive("PropertySingle", 1.79000000E+20)); - entity.addProperty(createPrimitive("PropertyDouble", -1.7900000000000000E+19)); - entity.addProperty(createPrimitive("PropertyDecimal", 34)); - entity.addProperty(createPrimitive("PropertyBinary", - new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF })); - entity.addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 3, 0, 0, 0))); - entity.addProperty(createPrimitive("PropertyDateTimeOffset", getDateTime(2012, 12, 3, 7, 16, 23))); - entity.addProperty(createPrimitive("PropertyDuration", 6)); - entity.addProperty(createPrimitive("PropertyGuid", GUID)); - entity.addProperty(createPrimitive("PropertyTimeOfDay", getTime(3, 26, 5))); - entitySet.getEntities().add(entity); + entitySet.getEntities().add(new EntityImpl() + .addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE)) + .addProperty(createPrimitive("PropertyString", "First Resource - positive values")) + .addProperty(createPrimitive("PropertyBoolean", true)) + .addProperty(createPrimitive("PropertyByte", 255)) + .addProperty(createPrimitive("PropertySByte", Byte.MAX_VALUE)) + .addProperty(createPrimitive("PropertyInt32", Integer.MAX_VALUE)) + .addProperty(createPrimitive("PropertyInt64", Long.MAX_VALUE)) + .addProperty(createPrimitive("PropertySingle", 1.79000000E+20)) + .addProperty(createPrimitive("PropertyDouble", -1.7900000000000000E+19)) + .addProperty(createPrimitive("PropertyDecimal", 34)) + .addProperty(createPrimitive("PropertyBinary", + new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF })) + .addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 3, 0, 0, 0))) + .addProperty(createPrimitive("PropertyDateTimeOffset", getDateTime(2012, 12, 3, 7, 16, 23))) + .addProperty(createPrimitive("PropertyDuration", 6)) + .addProperty(createPrimitive("PropertyGuid", GUID)) + .addProperty(createPrimitive("PropertyTimeOfDay", getTime(3, 26, 5)))); - entity = new EntityImpl(); - entity.addProperty(createPrimitive("PropertyInt16", Short.MIN_VALUE)); - entity.addProperty(createPrimitive("PropertyString", "Second Resource - negative values")); - entity.addProperty(createPrimitive("PropertyBoolean", false)); - entity.addProperty(createPrimitive("PropertyByte", 0)); - entity.addProperty(createPrimitive("PropertySByte", Byte.MIN_VALUE)); - entity.addProperty(createPrimitive("PropertyInt32", Integer.MIN_VALUE)); - entity.addProperty(createPrimitive("PropertyInt64", Long.MIN_VALUE)); - entity.addProperty(createPrimitive("PropertySingle", -1.79000000E+08)); - entity.addProperty(createPrimitive("PropertyDouble", -1.7900000000000000E+05)); - entity.addProperty(createPrimitive("PropertyDecimal", -34)); - entity.addProperty(createPrimitive("PropertyBinary", - new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF })); - entity.addProperty(createPrimitive("PropertyDate", getDateTime(2015, 11, 5, 0, 0, 0))); - entity.addProperty(createPrimitive("PropertyDateTimeOffset", getDateTime(2005, 12, 3, 7, 17, 8))); - entity.addProperty(createPrimitive("PropertyDuration", 9)); - entity.addProperty(createPrimitive("PropertyGuid", UUID.fromString("76543201-23ab-cdef-0123-456789dddfff"))); - entity.addProperty(createPrimitive("PropertyTimeOfDay", getTime(23, 49, 14))); - entitySet.getEntities().add(entity); + entitySet.getEntities().add(new EntityImpl() + .addProperty(createPrimitive("PropertyInt16", Short.MIN_VALUE)) + .addProperty(createPrimitive("PropertyString", "Second Resource - negative values")) + .addProperty(createPrimitive("PropertyBoolean", false)) + .addProperty(createPrimitive("PropertyByte", 0)) + .addProperty(createPrimitive("PropertySByte", Byte.MIN_VALUE)) + .addProperty(createPrimitive("PropertyInt32", Integer.MIN_VALUE)) + .addProperty(createPrimitive("PropertyInt64", Long.MIN_VALUE)) + .addProperty(createPrimitive("PropertySingle", -1.79000000E+08)) + .addProperty(createPrimitive("PropertyDouble", -1.7900000000000000E+05)) + .addProperty(createPrimitive("PropertyDecimal", -34)) + .addProperty(createPrimitive("PropertyBinary", + new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF })) + .addProperty(createPrimitive("PropertyDate", getDateTime(2015, 11, 5, 0, 0, 0))) + .addProperty(createPrimitive("PropertyDateTimeOffset", getDateTime(2005, 12, 3, 7, 17, 8))) + .addProperty(createPrimitive("PropertyDuration", 9)) + .addProperty(createPrimitive("PropertyGuid", UUID.fromString("76543201-23ab-cdef-0123-456789dddfff"))) + .addProperty(createPrimitive("PropertyTimeOfDay", getTime(23, 49, 14)))); - entity = new EntityImpl(); - entity.addProperty(createPrimitive("PropertyInt16", 0)); - entity.addProperty(createPrimitive("PropertyString", "")); - entity.addProperty(createPrimitive("PropertyBoolean", false)); - entity.addProperty(createPrimitive("PropertyByte", 0)); - entity.addProperty(createPrimitive("PropertySByte", 0)); - entity.addProperty(createPrimitive("PropertyInt32", 0)); - entity.addProperty(createPrimitive("PropertyInt64", 0)); - entity.addProperty(createPrimitive("PropertySingle", 0)); - entity.addProperty(createPrimitive("PropertyDouble", 0)); - entity.addProperty(createPrimitive("PropertyDecimal", 0)); - entity.addProperty(createPrimitive("PropertyBinary", new byte[] {})); - entity.addProperty(createPrimitive("PropertyDate", getDateTime(1970, 1, 1, 0, 0, 0))); - entity.addProperty(createPrimitive("PropertyDateTimeOffset", getDateTime(2005, 12, 3, 0, 0, 0))); - entity.addProperty(createPrimitive("PropertyDuration", 0)); - entity.addProperty(createPrimitive("PropertyGuid", UUID.fromString("76543201-23ab-cdef-0123-456789cccddd"))); - entity.addProperty(createPrimitive("PropertyTimeOfDay", getTime(0, 1, 1))); - entitySet.getEntities().add(entity); + entitySet.getEntities().add(new EntityImpl() + .addProperty(createPrimitive("PropertyInt16", 0)) + .addProperty(createPrimitive("PropertyString", "")) + .addProperty(createPrimitive("PropertyBoolean", false)) + .addProperty(createPrimitive("PropertyByte", 0)) + .addProperty(createPrimitive("PropertySByte", 0)) + .addProperty(createPrimitive("PropertyInt32", 0)) + .addProperty(createPrimitive("PropertyInt64", 0)) + .addProperty(createPrimitive("PropertySingle", 0)) + .addProperty(createPrimitive("PropertyDouble", 0)) + .addProperty(createPrimitive("PropertyDecimal", 0)) + .addProperty(createPrimitive("PropertyBinary", new byte[] {})) + .addProperty(createPrimitive("PropertyDate", getDateTime(1970, 1, 1, 0, 0, 0))) + .addProperty(createPrimitive("PropertyDateTimeOffset", getDateTime(2005, 12, 3, 0, 0, 0))) + .addProperty(createPrimitive("PropertyDuration", 0)) + .addProperty(createPrimitive("PropertyGuid", UUID.fromString("76543201-23ab-cdef-0123-456789cccddd"))) + .addProperty(createPrimitive("PropertyTimeOfDay", getTime(0, 1, 1)))); return entitySet; } @@ -281,46 +280,49 @@ public class DataProvider { private EntitySet createESCollAllPrim() { EntitySet entitySet = new EntitySetImpl(); + entitySet.getEntities().add(new EntityImpl() + .addProperty(createPrimitive("PropertyInt16", 1)) + .addProperty(createCollection("CollPropertyString", + "Employee1@company.example", "Employee2@company.example", "Employee3@company.example")) + .addProperty(createCollection("CollPropertyBoolean", true, false, true)) + .addProperty(createCollection("CollPropertyByte", 50, 200, 249)) + .addProperty(createCollection("CollPropertySByte", -120, 120, 126)) + .addProperty(createCollection("CollPropertyInt16", 1000, 2000, 30112)) + .addProperty(createCollection("CollPropertyInt32", 23232323, 11223355, 10000001)) + .addProperty(createCollection("CollPropertyInt64", 929292929292L, 333333333333L, 444444444444L)) + .addProperty(createCollection("CollPropertySingle", 1.79000000E+03, 2.66000000E+04, 3.21000000E+03)) + .addProperty(createCollection("CollPropertyDouble", + -1.7900000000000000E+04, -2.7800000000000000E+07, 3.2100000000000000E+03)) + .addProperty(createCollection("CollPropertyDecimal", 12, -2, 1234)) + .addProperty(createCollection("CollPropertyBinary", + new byte[] { (byte) 0xAB, (byte) 0xCD, (byte) 0xEF }, + new byte[] { 0x01, 0x23, 0x45 }, + new byte[] { 0x54, 0x67, (byte) 0x89 })) + .addProperty(createCollection("CollPropertyDate", + getDateTime(1958, 12, 3, 0, 0, 0), + getDateTime(1999, 8, 5, 0, 0, 0), + getDateTime(2013, 6, 25, 0, 0, 0))) + .addProperty(createCollection("CollPropertyDateTimeOffset", + getDateTime(2015, 8, 12, 3, 8, 34), + getDateTime(1970, 3, 28, 12, 11, 10), + getDateTime(1948, 2, 17, 9, 9, 9))) + .addProperty(createCollection("CollPropertyDuration", 13, 19680, 3600)) + .addProperty(createCollection("CollPropertyGuid", + UUID.fromString("ffffff67-89ab-cdef-0123-456789aaaaaa"), + UUID.fromString("eeeeee67-89ab-cdef-0123-456789bbbbbb"), + UUID.fromString("cccccc67-89ab-cdef-0123-456789cccccc"))) + .addProperty(createCollection("CollPropertyTimeOfDay", + getTime(4, 14, 13), getTime(23, 59, 59), getTime(1, 12, 33)))); + Entity entity = new EntityImpl(); - entity.addProperty(createPrimitive("PropertyInt16", 1)); - entity.addProperty(createCollection("CollPropertyString", - "Employee1@company.example", "Employee2@company.example", "Employee3@company.example")); - entity.addProperty(createCollection("CollPropertyBoolean", true, false, true)); - entity.addProperty(createCollection("CollPropertyByte", 50, 200, 249)); - entity.addProperty(createCollection("CollPropertySByte", -120, 120, 126)); - entity.addProperty(createCollection("CollPropertyInt16", 1000, 2000, 30112)); - entity.addProperty(createCollection("CollPropertyInt32", 23232323, 11223355, 10000001)); - entity.addProperty(createCollection("CollPropertyInt64", 929292929292L, 333333333333L, 444444444444L)); - entity.addProperty(createCollection("CollPropertySingle", 1.79000000E+03, 2.66000000E+04, 3.21000000E+03)); - entity.addProperty(createCollection("CollPropertyDouble", - -1.7900000000000000E+04, -2.7800000000000000E+07, 3.2100000000000000E+03)); - entity.addProperty(createCollection("CollPropertyDecimal", 12, -2, 1234)); - entity.addProperty(createCollection("CollPropertyBinary", - new byte[] { (byte) 0xAB, (byte) 0xCD, (byte) 0xEF }, - new byte[] { 0x01, 0x23, 0x45 }, - new byte[] { 0x54, 0x67, (byte) 0x89 })); - entity.addProperty(createCollection("CollPropertyDate", - getDateTime(1958, 12, 3, 0, 0, 0), getDateTime(1999, 8, 5, 0, 0, 0), getDateTime(2013, 6, 25, 0, 0, 0))); - entity.addProperty(createCollection("CollPropertyDateTimeOffset", - getDateTime(2015, 8, 12, 3, 8, 34), getDateTime(1970, 3, 28, 12, 11, 10), getDateTime(1948, 2, 17, 9, 9, 9))); - entity.addProperty(createCollection("CollPropertyDuration", 13, 19680, 3600)); - entity.addProperty(createCollection("CollPropertyGuid", - UUID.fromString("ffffff67-89ab-cdef-0123-456789aaaaaa"), - UUID.fromString("eeeeee67-89ab-cdef-0123-456789bbbbbb"), - UUID.fromString("cccccc67-89ab-cdef-0123-456789cccccc"))); - entity.addProperty(createCollection("CollPropertyTimeOfDay", - getTime(4, 14, 13), getTime(23, 59, 59), getTime(1, 12, 33))); + entity.getProperties().addAll(entitySet.getEntities().get(0).getProperties()); + entity.getProperties().set(0, createPrimitive("PropertyInt16", 2)); entitySet.getEntities().add(entity); - Entity entity2 = new EntityImpl(); - entity2.getProperties().addAll(entity.getProperties()); - entity2.getProperties().set(0, createPrimitive("PropertyInt16", 2)); - entitySet.getEntities().add(entity2); - - entity2 = new EntityImpl(); - entity2.getProperties().addAll(entity.getProperties()); - entity2.getProperties().set(0, createPrimitive("PropertyInt16", 3)); - entitySet.getEntities().add(entity2); + entity = new EntityImpl(); + entity.getProperties().addAll(entitySet.getEntities().get(0).getProperties()); + entity.getProperties().set(0, createPrimitive("PropertyInt16", 3)); + entitySet.getEntities().add(entity); return entitySet; } @@ -383,36 +385,62 @@ public class DataProvider { private EntitySet createESAllKey() { EntitySet entitySet = new EntitySetImpl(); + entitySet.getEntities().add(new EntityImpl() + .addProperty(createPrimitive("PropertyString", "First")) + .addProperty(createPrimitive("PropertyBoolean", true)) + .addProperty(createPrimitive("PropertyByte", 255)) + .addProperty(createPrimitive("PropertySByte", Byte.MAX_VALUE)) + .addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE)) + .addProperty(createPrimitive("PropertyInt32", Integer.MAX_VALUE)) + .addProperty(createPrimitive("PropertyInt64", Long.MAX_VALUE)) + .addProperty(createPrimitive("PropertyDecimal", 34)) + .addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 3, 0, 0, 0))) + .addProperty(createPrimitive("PropertyDateTimeOffset", getDateTime(2012, 12, 3, 7, 16, 23))) + .addProperty(createPrimitive("PropertyDuration", 6)) + .addProperty(createPrimitive("PropertyGuid", GUID)) + .addProperty(createPrimitive("PropertyTimeOfDay", getTime(2, 48, 21)))); + + entitySet.getEntities().add(new EntityImpl() + .addProperty(createPrimitive("PropertyString", "Second")) + .addProperty(createPrimitive("PropertyBoolean", true)) + .addProperty(createPrimitive("PropertyByte", 254)) + .addProperty(createPrimitive("PropertySByte", 124)) + .addProperty(createPrimitive("PropertyInt16", 32764)) + .addProperty(createPrimitive("PropertyInt32", 2147483644)) + .addProperty(createPrimitive("PropertyInt64", 9223372036854775804L)) + .addProperty(createPrimitive("PropertyDecimal", 34)) + .addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 3, 0, 0, 0))) + .addProperty(createPrimitive("PropertyDateTimeOffset", getDateTime(2012, 12, 3, 7, 16, 23))) + .addProperty(createPrimitive("PropertyDuration", 6)) + .addProperty(createPrimitive("PropertyGuid", GUID)) + .addProperty(createPrimitive("PropertyTimeOfDay", getTime(2, 48, 21)))); + + return entitySet; + } + + private EntitySet createESCompComp() { + EntitySet entitySet = new EntitySetImpl(); + Entity entity = new EntityImpl(); - entity.addProperty(createPrimitive("PropertyString", "First")); - entity.addProperty(createPrimitive("PropertyBoolean", true)); - entity.addProperty(createPrimitive("PropertyByte", 255)); - entity.addProperty(createPrimitive("PropertySByte", Byte.MAX_VALUE)); - entity.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE)); - entity.addProperty(createPrimitive("PropertyInt32", Integer.MAX_VALUE)); - entity.addProperty(createPrimitive("PropertyInt64", Long.MAX_VALUE)); - entity.addProperty(createPrimitive("PropertyDecimal", 34)); - entity.addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 3, 0, 0, 0))); - entity.addProperty(createPrimitive("PropertyDateTimeOffset", getDateTime(2012, 12, 3, 7, 16, 23))); - entity.addProperty(createPrimitive("PropertyDuration", 6)); - entity.addProperty(createPrimitive("PropertyGuid", GUID)); - entity.addProperty(createPrimitive("PropertyTimeOfDay", getTime(2, 48, 21))); + entity.addProperty(createPrimitive("PropertyInt16", 1)); + LinkedComplexValue complexValueInner = new LinkedComplexValueImpl(); + complexValueInner.getValue().add(createPrimitive("PropertyInt16", 123)); + complexValueInner.getValue().add(createPrimitive("PropertyString", "String 1")); + LinkedComplexValue complexValueOuter = new LinkedComplexValueImpl(); + complexValueOuter.getValue().add( + new PropertyImpl(null, "PropertyComp", ValueType.LINKED_COMPLEX, complexValueInner)); + entity.addProperty(new PropertyImpl(null, "PropertyComp", ValueType.LINKED_COMPLEX, complexValueOuter)); entitySet.getEntities().add(entity); entity = new EntityImpl(); - entity.addProperty(createPrimitive("PropertyString", "Second")); - entity.addProperty(createPrimitive("PropertyBoolean", true)); - entity.addProperty(createPrimitive("PropertyByte", 254)); - entity.addProperty(createPrimitive("PropertySByte", 124)); - entity.addProperty(createPrimitive("PropertyInt16", 32764)); - entity.addProperty(createPrimitive("PropertyInt32", 2147483644)); - entity.addProperty(createPrimitive("PropertyInt64", 9223372036854775804L)); - entity.addProperty(createPrimitive("PropertyDecimal", 34)); - entity.addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 3, 0, 0, 0))); - entity.addProperty(createPrimitive("PropertyDateTimeOffset", getDateTime(2012, 12, 3, 7, 16, 23))); - entity.addProperty(createPrimitive("PropertyDuration", 6)); - entity.addProperty(createPrimitive("PropertyGuid", GUID)); - entity.addProperty(createPrimitive("PropertyTimeOfDay", getTime(2, 48, 21))); + entity.addProperty(createPrimitive("PropertyInt16", 2)); + complexValueInner = new LinkedComplexValueImpl(); + complexValueInner.getValue().add(createPrimitive("PropertyInt16", 987)); + complexValueInner.getValue().add(createPrimitive("PropertyString", "String 2")); + complexValueOuter = new LinkedComplexValueImpl(); + complexValueOuter.getValue().add( + new PropertyImpl(null, "PropertyComp", ValueType.LINKED_COMPLEX, complexValueInner)); + entity.addProperty(new PropertyImpl(null, "PropertyComp", ValueType.LINKED_COMPLEX, complexValueOuter)); entitySet.getEntities().add(entity); return entitySet; @@ -444,6 +472,26 @@ public class DataProvider { return entitySet; } + private void linkESTwoPrim() { + EntitySet entitySet = data.get("ESTwoPrim"); + final List targetEntities = data.get("ESAllPrim").getEntities(); + + setLinks(entitySet.getEntities().get(1), "NavPropertyETAllPrimMany", targetEntities.subList(1, 3)); + + setLink(entitySet.getEntities().get(3), "NavPropertyETAllPrimOne", targetEntities.get(0)); + } + + private void linkESAllPrim() { + EntitySet entitySet = data.get("ESAllPrim"); + final List targetEntities = data.get("ESTwoPrim").getEntities(); + + setLinks(entitySet.getEntities().get(0), "NavPropertyETTwoPrimMany", targetEntities.subList(1, 2)); + setLink(entitySet.getEntities().get(0), "NavPropertyETTwoPrimOne", targetEntities.get(3)); + + setLinks(entitySet.getEntities().get(2), "NavPropertyETTwoPrimMany", + Arrays.asList(targetEntities.get(0), targetEntities.get(2), targetEntities.get(3))); + } + private Property createPrimitive(final String name, final Object value) { return new PropertyImpl(null, name, ValueType.PRIMITIVE, value); } @@ -475,4 +523,20 @@ public class DataProvider { timestamp.setNanos(nanosecond); return timestamp; } + + private void setLink(Entity entity, final String navigationPropertyName, final Entity target) { + Link link = new LinkImpl(); + link.setTitle(navigationPropertyName); + link.setInlineEntity(target); + entity.getNavigationLinks().add(link); + } + + private void setLinks(Entity entity, final String navigationPropertyName, final List targets) { + Link link = new LinkImpl(); + link.setTitle(navigationPropertyName); + EntitySet target = new EntitySetImpl(); + target.getEntities().addAll(targets); + link.setInlineEntitySet(target); + entity.getNavigationLinks().add(link); + } } 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 49a10ebbd..3917faeea 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 @@ -73,7 +73,7 @@ public class TechnicalProcessor implements EntityCollectionProcessor, EntityProc response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode()); } else { ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(requestedContentType)); - response.setContent(serializer.entitySet(edmEntitySet, entitySet, getContextUrl(edmEntitySet, false))); + response.setContent(serializer.entitySet(edmEntitySet, entitySet, getContextUrl(edmEntitySet, false), null)); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString()); } @@ -100,7 +100,7 @@ public class TechnicalProcessor implements EntityCollectionProcessor, EntityProc response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode()); } else { ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(requestedContentType)); - response.setContent(serializer.entity(edmEntitySet, entity, getContextUrl(edmEntitySet, true))); + response.setContent(serializer.entity(edmEntitySet, entity, getContextUrl(edmEntitySet, true), null)); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString()); } diff --git a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java index 581ec1dd4..e8be8adde 100644 --- a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java +++ b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java @@ -68,11 +68,20 @@ public class DataProviderTest { @Test public void esAllPrim() throws Exception { - EntitySet outSet = new DataProvider().readAll(esAllPrim); + final DataProvider data = new DataProvider(); + EntitySet outSet = data.readAll(esAllPrim); Assert.assertEquals(3, outSet.getEntities().size()); + Entity first = outSet.getEntities().get(0); Assert.assertEquals(16, first.getProperties().size()); + Assert.assertEquals(2, first.getNavigationLinks().size()); + final EntitySet target = first.getNavigationLink("NavPropertyETTwoPrimMany").getInlineEntitySet(); + Assert.assertNotNull(target); + Assert.assertEquals(1, target.getEntities().size()); + Assert.assertEquals(data.readAll(entityContainer.getEntitySet("ESTwoPrim")).getEntities().get(1), + target.getEntities().get(0)); + Assert.assertEquals(16, outSet.getEntities().get(1).getProperties().size()); Assert.assertEquals(16, outSet.getEntities().get(2).getProperties().size()); } @@ -120,7 +129,7 @@ public class DataProviderTest { Assert.assertEquals(2, linkedComplexValue.getValue().size()); Property lcProp = linkedComplexValue.getValue().get(0); Assert.assertFalse(lcProp.isCollection()); - Assert.assertEquals(Integer.valueOf("123"), lcProp.getValue()); + Assert.assertEquals(123, lcProp.getValue()); // Assert.assertEquals(4, outSet.getEntities().get(1).getProperties().size()); Assert.assertEquals(4, outSet.getEntities().get(2).getProperties().size()); 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 8e6d3ad26..e33e1dd2e 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 @@ -20,7 +20,9 @@ package org.apache.olingo.server.core.serializer.json; import java.io.InputStream; import java.net.URI; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.apache.commons.io.IOUtils; import org.apache.olingo.commons.api.data.ContextURL; @@ -31,16 +33,25 @@ import org.apache.olingo.commons.api.data.ValueType; 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.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.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializerException; +import org.apache.olingo.server.api.uri.UriInfoResource; +import org.apache.olingo.server.api.uri.UriResource; +import org.apache.olingo.server.api.uri.UriResourceProperty; +import org.apache.olingo.server.api.uri.queryoption.ExpandItem; +import org.apache.olingo.server.api.uri.queryoption.SelectItem; +import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.tecsvc.data.DataProvider; import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; import org.hamcrest.CoreMatchers; import org.junit.Assert; import org.junit.Test; +import org.mockito.Mockito; public class ODataJsonSerializerTest { @@ -55,7 +66,8 @@ public class ODataJsonSerializerTest { final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim"); final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); InputStream result = serializer.entity(edmEntitySet, entity, - ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()); + ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), + null); final String resultString = IOUtils.toString(result); final String expectedResult = "{" + "\"@odata.context\":\"$metadata#ESAllPrim/$entity\"," @@ -85,7 +97,7 @@ public class ODataJsonSerializerTest { Entity entity = data.readAll(edmEntitySet).getEntities().get(0); entity.getProperties().retainAll(Arrays.asList(entity.getProperties().get(0))); final String resultString = IOUtils.toString(serializer.entity(edmEntitySet, entity, - ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())); + ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null)); final String expectedResult = "{\"@odata.context\":\"$metadata#ESAllPrim/$entity\"," + "\"PropertyInt16\":32767," + "\"PropertyString\":null,\"PropertyBoolean\":null," @@ -104,7 +116,7 @@ public class ODataJsonSerializerTest { Entity entity = data.readAll(edmEntitySet).getEntities().get(0); entity.getProperties().clear(); serializer.entity(edmEntitySet, entity, - ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()); + ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null); } @Test @@ -114,7 +126,7 @@ public class ODataJsonSerializerTest { entity.getProperties().get(0).setValue(ValueType.PRIMITIVE, false); try { serializer.entity(edmEntitySet, entity, - ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()); + ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null); Assert.fail("Expected exception not thrown!"); } catch (final ODataSerializerException e) { Assert.assertEquals(ODataSerializerException.MessageKeys.WRONG_PROPERTY_VALUE, e.getMessageKey()); @@ -131,7 +143,7 @@ public class ODataJsonSerializerTest { entitySet.setCount(entitySet.getEntities().size()); entitySet.setNext(URI.create("/next")); InputStream result = serializer.entitySet(edmEntitySet, entitySet, - ContextURL.Builder.create().entitySet(edmEntitySet).build()); + ContextURL.Builder.create().entitySet(edmEntitySet).build(), null); final String resultString = IOUtils.toString(result); Assert.assertThat(resultString, CoreMatchers.startsWith("{" @@ -154,7 +166,7 @@ public class ODataJsonSerializerTest { final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); InputStream result = serializer.entity(edmEntitySet, entity, ContextURL.Builder.create().serviceRoot(URI.create("http://host/service/")) - .entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()); + .entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null); final String resultString = IOUtils.toString(result); final String expectedResult = "{" + "\"@odata.context\":\"http://host/service/$metadata#ESCollAllPrim/$entity\"," @@ -187,7 +199,7 @@ public class ODataJsonSerializerTest { final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCompAllPrim"); final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); InputStream result = serializer.entity(edmEntitySet, entity, - ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()); + ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null); final String resultString = IOUtils.toString(result); final String expectedResult = "{" + "\"@odata.context\":\"$metadata#ESCompAllPrim/$entity\"," @@ -218,7 +230,7 @@ public class ODataJsonSerializerTest { final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp"); final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); InputStream result = serializer.entity(edmEntitySet, entity, - ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()); + ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null); final String resultString = IOUtils.toString(result); final String expectedResult = "{" + "\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\"," @@ -239,7 +251,7 @@ public class ODataJsonSerializerTest { Entity entity = data.readAll(edmEntitySet).getEntities().get(0); entity.getProperties().retainAll(Arrays.asList(entity.getProperties().get(0))); final String resultString = IOUtils.toString(serializer.entity(edmEntitySet, entity, - ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())); + ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null)); final String expectedResult = "{\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\"," + "\"PropertyInt16\":32767," + "\"CollPropertyString\":null,\"PropertyComp\":null,\"CollPropertyComp\":null}"; @@ -251,7 +263,7 @@ public class ODataJsonSerializerTest { final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESTwoPrim"); final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) - .entity(edmEntitySet, entity, null); + .entity(edmEntitySet, entity, null, null); final String resultString = IOUtils.toString(result); final String expectedResult = "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}"; Assert.assertEquals(expectedResult, resultString); @@ -262,7 +274,7 @@ public class ODataJsonSerializerTest { final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESTwoPrim"); final EntitySet entitySet = data.readAll(edmEntitySet); InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) - .entitySet(edmEntitySet, entitySet, ContextURL.Builder.create().entitySet(edmEntitySet).build()); + .entitySet(edmEntitySet, entitySet, ContextURL.Builder.create().entitySet(edmEntitySet).build(), null); final String resultString = IOUtils.toString(result); final String expectedResult = "{\"value\":[" + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}," @@ -278,7 +290,7 @@ public class ODataJsonSerializerTest { Entity entity = data.readAll(edmEntitySet).getEntities().get(0); entity.setMediaETag("theMediaETag"); final String resultString = IOUtils.toString(serializer.entity(edmEntitySet, entity, - ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())); + ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null)); final String expectedResult = "{\"@odata.context\":\"$metadata#ESMedia/$entity\"," + "\"@odata.mediaEtag\":\"theMediaETag\",\"@odata.mediaContentType\":\"image/png\"," + "\"PropertyInt16\":1}"; @@ -290,7 +302,7 @@ public class ODataJsonSerializerTest { final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMedia"); final EntitySet entitySet = data.readAll(edmEntitySet); final String resultString = IOUtils.toString(serializer.entitySet(edmEntitySet, entitySet, - ContextURL.Builder.create().entitySet(edmEntitySet).build())); + ContextURL.Builder.create().entitySet(edmEntitySet).build(), null)); final String expectedResult = "{\"@odata.context\":\"$metadata#ESMedia\",\"value\":[" + "{\"@odata.mediaContentType\":\"image/png\",\"PropertyInt16\":1}," + "{\"@odata.mediaContentType\":\"image/bmp\",\"PropertyInt16\":2}," @@ -298,4 +310,115 @@ public class ODataJsonSerializerTest { + "{\"@odata.mediaContentType\":\"foo\",\"PropertyInt16\":4}]}"; Assert.assertEquals(expectedResult, resultString); } + + @Test + public void select() throws Exception { + final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim"); + final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); + final SelectItem selectItem1 = mockSelectItem(edmEntitySet, "PropertyDate"); + final SelectItem selectItem2 = mockSelectItem(edmEntitySet, "PropertyBoolean"); + final SelectOption select = mockSelectOption(Arrays.asList(selectItem1, selectItem2, selectItem2)); + ExpandItem options = Mockito.mock(ExpandItem.class); + Mockito.when(options.getSelectOption()).thenReturn(select); + InputStream result = + new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer + .entity(edmEntitySet, entity, + null, // ContextURL.Builder.create().entitySet(edmEntitySet).selectList("PropertyBoolean,PropertyDate") + // .suffix(Suffix.ENTITY).build(), + options); + final String resultString = IOUtils.toString(result); + final String expectedResult = "{" + // + "\"@odata.context\":\"$metadata#ESAllPrim(PropertyBoolean,PropertyDate)/$entity\"," + + "\"PropertyBoolean\":true,\"PropertyDate\":\"2012-12-03\"}"; + Assert.assertEquals(expectedResult, resultString); + } + + @Test + public void selectAll() throws Exception { + final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESTwoPrim"); + final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); + final SelectItem selectItem1 = mockSelectItem(edmEntitySet, "PropertyString"); + SelectItem selectItem2 = Mockito.mock(SelectItem.class); + Mockito.when(selectItem2.isStar()).thenReturn(true); + final SelectOption select = mockSelectOption(Arrays.asList(selectItem1, selectItem2)); + ExpandItem options = Mockito.mock(ExpandItem.class); + Mockito.when(options.getSelectOption()).thenReturn(select); + InputStream result = serializer.entity(edmEntitySet, entity, + ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), + options); + final String resultString = IOUtils.toString(result); + final String expectedResult = "{\"@odata.context\":\"$metadata#ESTwoPrim/$entity\"," + + "\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}"; + Assert.assertEquals(expectedResult, resultString); + } + + @Test + public void selectComplex() throws Exception { + final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCompComp"); + final EntitySet entitySet = data.readAll(edmEntitySet); + final SelectOption select = mockSelectOption(Arrays.asList( + mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp", "PropertyString"))); + ExpandItem options = Mockito.mock(ExpandItem.class); + Mockito.when(options.getSelectOption()).thenReturn(select); + InputStream result = + new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer + .entitySet(edmEntitySet, entitySet, + null, // ContextURL.Builder.create().entitySet(edmEntitySet) + // .selectList("PropertyComp/PropertyComp/PropertyString").build(), + options); + final String resultString = IOUtils.toString(result); + Assert.assertEquals("{" + // + "\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp/PropertyString)\"," + + "\"value\":[" + + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyString\":\"String 1\"}}}," + + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyString\":\"String 2\"}}}]}", + resultString); + } + + @Test + public void selectComplexTwice() throws Exception { + final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCompComp"); + final EntitySet entitySet = data.readAll(edmEntitySet); + final SelectOption select = mockSelectOption(Arrays.asList( + mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp", "PropertyString"), + mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp"))); + ExpandItem options = Mockito.mock(ExpandItem.class); + Mockito.when(options.getSelectOption()).thenReturn(select); + InputStream result = + new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer + .entitySet(edmEntitySet, entitySet, + null, // ContextURL.Builder.create().entitySet(edmEntitySet) + // .selectList("PropertyComp/PropertyComp").build(), + options); + final String resultString = IOUtils.toString(result); + Assert.assertEquals("{" + // + "\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp)\"," + + "\"value\":[" + + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyInt16\":123,\"PropertyString\":\"String 1\"}}}," + + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyInt16\":987,\"PropertyString\":\"String 2\"}}}]}", + resultString); + } + + private SelectItem mockSelectItem(final EdmEntitySet edmEntitySet, final String... names) { + EdmStructuredType type = edmEntitySet.getEntityType(); + List elements = new ArrayList(); + for (final String name : Arrays.asList(names)) { + UriResourceProperty element = Mockito.mock(UriResourceProperty.class); + final EdmProperty property = (EdmProperty) type.getProperty(name); + Mockito.when(element.getProperty()).thenReturn(property); + elements.add(element); + type = property.isPrimitive() ? null : (EdmStructuredType) property.getType(); + } + UriInfoResource resource = Mockito.mock(UriInfoResource.class); + Mockito.when(resource.getUriResourceParts()).thenReturn(elements); + SelectItem selectItem = Mockito.mock(SelectItem.class); + Mockito.when(selectItem.getResourcePath()).thenReturn(resource); + return selectItem; + } + + private SelectOption mockSelectOption(final List selectItems) { + SelectOption select = Mockito.mock(SelectOption.class); + Mockito.when(select.getSelectItems()).thenReturn(selectItems); + return select; + } }