OLINGO-1009 Changing serialization to allow for $levels

This commit is contained in:
shawkins 2016-09-07 09:39:25 -04:00
parent b1db030cb8
commit 68969d547d
4 changed files with 202 additions and 64 deletions

View File

@ -64,6 +64,7 @@ import org.apache.olingo.server.api.uri.UriHelper;
import org.apache.olingo.server.api.uri.queryoption.CountOption; import org.apache.olingo.server.api.uri.queryoption.CountOption;
import org.apache.olingo.server.api.uri.queryoption.ExpandItem; import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.LevelsExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.core.ODataWritableContent; import org.apache.olingo.server.core.ODataWritableContent;
import org.apache.olingo.server.core.serializer.AbstractODataSerializer; import org.apache.olingo.server.core.serializer.AbstractODataSerializer;
@ -73,6 +74,7 @@ import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder; import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper; import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper;
import org.apache.olingo.server.core.uri.UriHelperImpl; import org.apache.olingo.server.core.uri.UriHelperImpl;
import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
@ -164,10 +166,10 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
writeOperations(entitySet.getOperations(), json); writeOperations(entitySet.getOperations(), json);
json.writeFieldName(Constants.VALUE); json.writeFieldName(Constants.VALUE);
if (options == null) { if (options == null) {
writeEntitySet(metadata, entityType, entitySet, null, null, false, json); writeEntitySet(metadata, entityType, entitySet, null, null, null, false, json);
} else { } else {
writeEntitySet(metadata, entityType, entitySet, writeEntitySet(metadata, entityType, entitySet,
options.getExpand(), options.getSelect(), options.getWriteOnlyReferences(), json); options.getExpand(), null, options.getSelect(), options.getWriteOnlyReferences(), json);
} }
writeNextLink(entitySet, json); writeNextLink(entitySet, json);
@ -210,10 +212,10 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
} }
json.writeFieldName(Constants.VALUE); json.writeFieldName(Constants.VALUE);
if (options == null) { if (options == null) {
writeEntitySet(metadata, entityType, entitySet, null, null, false, json); writeEntitySet(metadata, entityType, entitySet, null, null, null, false, json);
} else { } else {
writeEntitySet(metadata, entityType, entitySet, writeEntitySet(metadata, entityType, entitySet,
options.getExpand(), options.getSelect(), options.getWriteOnlyReferences(), json); options.getExpand(), null, options.getSelect(), options.getWriteOnlyReferences(), json);
} }
// next link not supported by default for streaming results // next link not supported by default for streaming results
// writeNextLink(entitySet, json); // writeNextLink(entitySet, json);
@ -238,6 +240,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
JsonGenerator json = new JsonFactory().createGenerator(outputStream); JsonGenerator json = new JsonFactory().createGenerator(outputStream);
writeEntity(metadata, entityType, entity, contextURL, writeEntity(metadata, entityType, entity, contextURL,
options == null ? null : options.getExpand(), options == null ? null : options.getExpand(),
null,
options == null ? null : options.getSelect(), options == null ? null : options.getSelect(),
options == null ? false : options.getWriteOnlyReferences(), options == null ? false : options.getWriteOnlyReferences(),
json); json);
@ -264,7 +267,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
} }
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType, protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
final AbstractEntityCollection entitySet, final ExpandOption expand, final SelectOption select, final AbstractEntityCollection entitySet, final ExpandOption expand, Integer toDepth, final SelectOption select,
final boolean onlyReference, final JsonGenerator json) throws IOException, final boolean onlyReference, final JsonGenerator json) throws IOException,
SerializerException { SerializerException {
json.writeStartArray(); json.writeStartArray();
@ -274,7 +277,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
json.writeStringField(Constants.JSON_ID, getEntityId(entity)); json.writeStringField(Constants.JSON_ID, getEntityId(entity));
json.writeEndObject(); json.writeEndObject();
} else { } else {
writeEntity(metadata, entityType, entity, null, expand, select, false, json); writeEntity(metadata, entityType, entity, null, expand, toDepth, select, false, json);
} }
} }
json.writeEndArray(); json.writeEndArray();
@ -308,8 +311,8 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
} }
public void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType, final Entity entity, public void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType, final Entity entity,
final ContextURL contextURL, final ExpandOption expand, final SelectOption select, final boolean onlyReference, final ContextURL contextURL, final ExpandOption expand, Integer toDepth,
final JsonGenerator json) final SelectOption select, final boolean onlyReference, final JsonGenerator json)
throws IOException, SerializerException { throws IOException, SerializerException {
json.writeStartObject(); json.writeStartObject();
if (!isODataMetadataNone) { if (!isODataMetadataNone) {
@ -357,7 +360,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
} }
writeProperties(metadata, resolvedType, entity.getProperties(), select, json); writeProperties(metadata, resolvedType, entity.getProperties(), select, json);
writeNavigationProperties(metadata, resolvedType, entity, expand, json); writeNavigationProperties(metadata, resolvedType, entity, expand, toDepth, json);
writeOperations(entity.getOperations(), json); writeOperations(entity.getOperations(), json);
json.writeEndObject(); json.writeEndObject();
} }
@ -442,24 +445,57 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
} }
protected void writeNavigationProperties(final ServiceMetadata metadata, protected void writeNavigationProperties(final ServiceMetadata metadata,
final EdmStructuredType type, final Linked linked, final ExpandOption expand, final EdmStructuredType type, final Linked linked, final ExpandOption expand, final Integer toDepth,
final JsonGenerator json) throws SerializerException, IOException { final JsonGenerator json) throws SerializerException, IOException {
if (ExpandSelectHelper.hasExpand(expand)) { if ((toDepth != null && toDepth > 1) || (toDepth == null && ExpandSelectHelper.hasExpand(expand))) {
final boolean expandAll = ExpandSelectHelper.isExpandAll(expand); final ExpandItem expandAll = ExpandSelectHelper.getExpandAll(expand);
final Set<String> expanded = expandAll ? new HashSet<String>() :
ExpandSelectHelper.getExpandedPropertyNames(expand.getExpandItems());
for (final String propertyName : type.getNavigationPropertyNames()) { for (final String propertyName : type.getNavigationPropertyNames()) {
if (expandAll || expanded.contains(propertyName)) { final ExpandItem innerOptions = ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
if (toDepth != null) {
final EdmNavigationProperty property = type.getNavigationProperty(propertyName); final EdmNavigationProperty property = type.getNavigationProperty(propertyName);
final Link navigationLink = linked.getNavigationLink(property.getName()); final Link navigationLink = linked.getNavigationLink(property.getName());
final ExpandItem innerOptions = expandAll ? null :
ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
if (innerOptions != null && innerOptions.getLevelsOption() != null) {
throw new SerializerException("Expand option $levels is not supported.",
SerializerException.MessageKeys.NOT_IMPLEMENTED);
}
writeExpandedNavigationProperty(metadata, property, navigationLink, writeExpandedNavigationProperty(metadata, property, navigationLink,
innerOptions == null ? null : innerOptions.getExpandOption(), expand, toDepth-1,
innerOptions == null ? null : innerOptions.getSelectOption(),
innerOptions == null ? null : innerOptions.getCountOption(),
innerOptions == null ? false : innerOptions.hasCountPath(),
innerOptions == null ? false : innerOptions.isRef(),
json);
continue;
}
Integer levels = null;
if (expandAll != null || innerOptions != null) {
final EdmNavigationProperty property = type.getNavigationProperty(propertyName);
final Link navigationLink = linked.getNavigationLink(property.getName());
ExpandOption childExpand = null;
LevelsExpandOption levelsOption = null;
if (innerOptions != null) {
levelsOption = innerOptions.getLevelsOption();
if (levelsOption == null) {
childExpand = innerOptions.getExpandOption();
} else {
ExpandOptionImpl expandOptionImpl = new ExpandOptionImpl();
expandOptionImpl.addExpandItem(innerOptions);
childExpand = expandOptionImpl;
}
} else if (expandAll != null) {
levels = 1;
levelsOption = expandAll.getLevelsOption();
ExpandOptionImpl expandOptionImpl = new ExpandOptionImpl();
expandOptionImpl.addExpandItem(expandAll);
childExpand = expandOptionImpl;
}
if (levelsOption != null) {
if (levelsOption.isMax()) {
levels = Integer.MAX_VALUE;
} else {
levels = levelsOption.getValue();
}
}
writeExpandedNavigationProperty(metadata, property, navigationLink,
childExpand, levels,
innerOptions == null ? null : innerOptions.getSelectOption(), innerOptions == null ? null : innerOptions.getSelectOption(),
innerOptions == null ? null : innerOptions.getCountOption(), innerOptions == null ? null : innerOptions.getCountOption(),
innerOptions == null ? false : innerOptions.hasCountPath(), innerOptions == null ? false : innerOptions.hasCountPath(),
@ -484,7 +520,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
protected void writeExpandedNavigationProperty( protected void writeExpandedNavigationProperty(
final ServiceMetadata metadata, final EdmNavigationProperty property, final ServiceMetadata metadata, final EdmNavigationProperty property,
final Link navigationLink, final ExpandOption innerExpand, final Link navigationLink, final ExpandOption innerExpand,
final SelectOption innerSelect, final CountOption innerCount, Integer toDepth, final SelectOption innerSelect, final CountOption innerCount,
final boolean writeOnlyCount, final boolean writeOnlyRef, final boolean writeOnlyCount, final boolean writeOnlyRef,
final JsonGenerator json) throws IOException, SerializerException { final JsonGenerator json) throws IOException, SerializerException {
@ -508,7 +544,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
writeInlineCount(property.getName(), navigationLink.getInlineEntitySet().getCount(), json); writeInlineCount(property.getName(), navigationLink.getInlineEntitySet().getCount(), json);
} }
json.writeFieldName(property.getName()); json.writeFieldName(property.getName());
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand, writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand, toDepth,
innerSelect, writeOnlyRef, json); innerSelect, writeOnlyRef, json);
} }
} }
@ -518,7 +554,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
json.writeNull(); json.writeNull();
} else { } else {
writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null, writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null,
innerExpand, innerSelect, writeOnlyRef, json); innerExpand, toDepth, innerSelect, writeOnlyRef, json);
} }
} }
} }
@ -847,7 +883,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
writeProperties(metadata, type, values, options == null ? null : options.getSelect(), json); writeProperties(metadata, type, values, options == null ? null : options.getSelect(), json);
if (!property.isNull() && property.isComplex()) { if (!property.isNull() && property.isComplex()) {
writeNavigationProperties(metadata, type, property.asComplex(), writeNavigationProperties(metadata, type, property.asComplex(),
options == null ? null : options.getExpand(), json); options == null ? null : options.getExpand(), null, json);
} }
json.writeEndObject(); json.writeEndObject();

View File

@ -122,6 +122,15 @@ public abstract class ExpandSelectHelper {
return false; return false;
} }
public static ExpandItem getExpandAll(final ExpandOption expand) {
for (final ExpandItem item : expand.getExpandItems()) {
if (item.isStar()) {
return item;
}
}
return null;
}
public static Set<String> getExpandedPropertyNames(final List<ExpandItem> expandItems) public static Set<String> getExpandedPropertyNames(final List<ExpandItem> expandItems)
throws SerializerException { throws SerializerException {
Set<String> expanded = new HashSet<String>(); Set<String> expanded = new HashSet<String>();
@ -137,6 +146,9 @@ public abstract class ExpandSelectHelper {
public static ExpandItem getExpandItem(final List<ExpandItem> expandItems, final String propertyName) { public static ExpandItem getExpandItem(final List<ExpandItem> expandItems, final String propertyName) {
for (final ExpandItem item : expandItems) { for (final ExpandItem item : expandItems) {
if (item.isStar()) {
continue;
}
final UriResource resource = item.getResourcePath().getUriResourceParts().get(0); final UriResource resource = item.getResourcePath().getUriResourceParts().get(0);
if (resource instanceof UriResourceNavigation if (resource instanceof UriResourceNavigation
&& propertyName.equals(((UriResourceNavigation) resource).getProperty().getName())) { && propertyName.equals(((UriResourceNavigation) resource).getProperty().getName())) {

View File

@ -70,6 +70,7 @@ import org.apache.olingo.server.api.serializer.SerializerStreamResult;
import org.apache.olingo.server.api.uri.queryoption.CountOption; import org.apache.olingo.server.api.uri.queryoption.CountOption;
import org.apache.olingo.server.api.uri.queryoption.ExpandItem; import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.LevelsExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.core.ODataWritableContent; import org.apache.olingo.server.core.ODataWritableContent;
import org.apache.olingo.server.core.serializer.AbstractODataSerializer; import org.apache.olingo.server.core.serializer.AbstractODataSerializer;
@ -77,6 +78,7 @@ import org.apache.olingo.server.core.serializer.SerializerResultImpl;
import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer; import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder; import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper; import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper;
import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
public class ODataXmlSerializer extends AbstractODataSerializer { public class ODataXmlSerializer extends AbstractODataSerializer {
@ -257,10 +259,11 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
boolean writeOnlyRef = (options != null && options.getWriteOnlyReferences()); boolean writeOnlyRef = (options != null && options.getWriteOnlyReferences());
if (options == null) { if (options == null) {
writeEntitySet(metadata, entityType, entitySet, null, null, null, writer, writeOnlyRef); writeEntitySet(metadata, entityType, entitySet, null, null, null, null, writer, writeOnlyRef);
} else { } else {
writeEntitySet(metadata, entityType, entitySet, writeEntitySet(metadata, entityType, entitySet,
options.getExpand(), options.getSelect(), options.xml10InvalidCharReplacement(), writer, writeOnlyRef); options.getExpand(), null,
options.getSelect(), options.xml10InvalidCharReplacement(), writer, writeOnlyRef);
} }
writer.writeEndElement(); writer.writeEndElement();
@ -314,10 +317,11 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
boolean writeOnlyRef = (options != null && options.getWriteOnlyReferences()); boolean writeOnlyRef = (options != null && options.getWriteOnlyReferences());
if (options == null) { if (options == null) {
writeEntitySet(metadata, entityType, entitySet, null, null, null, writer, writeOnlyRef); writeEntitySet(metadata, entityType, entitySet, null, null, null, null, writer, writeOnlyRef);
} else { } else {
writeEntitySet(metadata, entityType, entitySet, writeEntitySet(metadata, entityType, entitySet,
options.getExpand(), options.getSelect(), options.xml10InvalidCharReplacement(), writer, writeOnlyRef); options.getExpand(), null,
options.getSelect(), options.xml10InvalidCharReplacement(), writer, writeOnlyRef);
} }
writer.writeEndElement(); writer.writeEndElement();
@ -356,6 +360,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
writer.writeStartDocument(DEFAULT_CHARSET, "1.0"); writer.writeStartDocument(DEFAULT_CHARSET, "1.0");
writeEntity(metadata, entityType, entity, contextURL, writeEntity(metadata, entityType, entity, contextURL,
options == null ? null : options.getExpand(), options == null ? null : options.getExpand(),
null,
options == null ? null : options.getSelect(), options == null ? null : options.getSelect(),
options == null ? null : options.xml10InvalidCharReplacement(), options == null ? null : options.xml10InvalidCharReplacement(),
writer, true, false); writer, true, false);
@ -397,17 +402,18 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
} }
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType, protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
final AbstractEntityCollection entitySet, final ExpandOption expand, final SelectOption select, final AbstractEntityCollection entitySet, final ExpandOption expand,
final Integer toDepth, final SelectOption select,
final String xml10InvalidCharReplacement,final XMLStreamWriter writer, final boolean writeOnlyRef) final String xml10InvalidCharReplacement,final XMLStreamWriter writer, final boolean writeOnlyRef)
throws XMLStreamException, SerializerException { throws XMLStreamException, SerializerException {
for (final Entity entity : entitySet) { for (final Entity entity : entitySet) {
writeEntity(metadata, entityType, entity, null, expand, select, writeEntity(metadata, entityType, entity, null, expand, toDepth, select,
xml10InvalidCharReplacement, writer, false, writeOnlyRef); xml10InvalidCharReplacement, writer, false, writeOnlyRef);
} }
} }
protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType, protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
final Entity entity, final ContextURL contextURL, final ExpandOption expand, final Entity entity, final ContextURL contextURL, final ExpandOption expand, final Integer toDepth,
final SelectOption select, final String xml10InvalidCharReplacement, final SelectOption select, final String xml10InvalidCharReplacement,
final XMLStreamWriter writer, final boolean top, final boolean writeOnlyRef) final XMLStreamWriter writer, final boolean top, final boolean writeOnlyRef)
throws XMLStreamException, SerializerException { throws XMLStreamException, SerializerException {
@ -466,7 +472,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
} }
EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType()); EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType());
writeNavigationProperties(metadata, resolvedType, entity, expand, xml10InvalidCharReplacement, writer); writeNavigationProperties(metadata, resolvedType, entity, expand, toDepth, xml10InvalidCharReplacement, writer);
writer.writeStartElement(ATOM, Constants.ATOM_ELEM_CATEGORY, NS_ATOM); writer.writeStartElement(ATOM, Constants.ATOM_ELEM_CATEGORY, NS_ATOM);
writer.writeAttribute(Constants.ATOM_ATTR_SCHEME, Constants.NS_SCHEME); writer.writeAttribute(Constants.ATOM_ATTR_SCHEME, Constants.NS_SCHEME);
@ -591,36 +597,71 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
} }
protected void writeNavigationProperties(final ServiceMetadata metadata, protected void writeNavigationProperties(final ServiceMetadata metadata,
final EdmStructuredType type, final Linked linked, final ExpandOption expand, final EdmStructuredType type, final Linked linked, final ExpandOption expand, final Integer toDepth,
final String xml10InvalidCharReplacement, final XMLStreamWriter writer) final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
throws SerializerException, XMLStreamException { throws SerializerException, XMLStreamException {
if (ExpandSelectHelper.hasExpand(expand)) { if ((toDepth != null && toDepth > 1) || (toDepth == null && ExpandSelectHelper.hasExpand(expand))) {
final boolean expandAll = ExpandSelectHelper.isExpandAll(expand); final ExpandItem expandAll = ExpandSelectHelper.getExpandAll(expand);
final Set<String> expanded = expandAll ? new HashSet<String>() :
ExpandSelectHelper.getExpandedPropertyNames(expand.getExpandItems());
for (final String propertyName : type.getNavigationPropertyNames()) { for (final String propertyName : type.getNavigationPropertyNames()) {
final EdmNavigationProperty property = type.getNavigationProperty(propertyName); final ExpandItem innerOptions = ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
final Link navigationLink = getOrCreateLink(linked, propertyName); if (toDepth != null) {
if (expandAll || expanded.contains(propertyName)) { final EdmNavigationProperty property = type.getNavigationProperty(propertyName);
final ExpandItem innerOptions = expandAll ? null : final Link navigationLink = getOrCreateLink(linked, propertyName);
ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName); writeLink(writer, navigationLink, false);
if (innerOptions != null && innerOptions.getLevelsOption() != null) { writer.writeStartElement(METADATA, Constants.ATOM_ELEM_INLINE, NS_METADATA);
throw new SerializerException("Expand option $levels is not supported.", writeExpandedNavigationProperty(metadata, property, navigationLink,
SerializerException.MessageKeys.NOT_IMPLEMENTED); expand, toDepth - 1,
innerOptions == null ? null : innerOptions.getSelectOption(),
innerOptions == null ? null : innerOptions.getCountOption(),
innerOptions == null ? false : innerOptions.hasCountPath(),
innerOptions == null ? false : innerOptions.isRef(),
xml10InvalidCharReplacement, writer);
writer.writeEndElement();
writer.writeEndElement();
continue;
}
Integer levels = null;
if (expandAll != null || innerOptions != null) {
final EdmNavigationProperty property = type.getNavigationProperty(propertyName);
final Link navigationLink = getOrCreateLink(linked, propertyName);
ExpandOption childExpand = null;
LevelsExpandOption levelsOption = null;
if (innerOptions != null) {
levelsOption = innerOptions.getLevelsOption();
if (levelsOption == null) {
childExpand = innerOptions.getExpandOption();
} else {
ExpandOptionImpl expandOptionImpl = new ExpandOptionImpl();
expandOptionImpl.addExpandItem(innerOptions);
childExpand = expandOptionImpl;
}
} else if (expandAll != null) {
levels = 1;
levelsOption = expandAll.getLevelsOption();
ExpandOptionImpl expandOptionImpl = new ExpandOptionImpl();
expandOptionImpl.addExpandItem(expandAll);
childExpand = expandOptionImpl;
} }
if (navigationLink != null) {
writeLink(writer, navigationLink, false); if (levelsOption != null) {
writer.writeStartElement(METADATA, Constants.ATOM_ELEM_INLINE, NS_METADATA); if (levelsOption.isMax()) {
writeExpandedNavigationProperty(metadata, property, navigationLink, levels = Integer.MAX_VALUE;
innerOptions == null ? null : innerOptions.getExpandOption(), } else {
innerOptions == null ? null : innerOptions.getSelectOption(), levels = levelsOption.getValue();
innerOptions == null ? null : innerOptions.getCountOption(), }
innerOptions == null ? false : innerOptions.hasCountPath(),
innerOptions == null ? false : innerOptions.isRef(),
xml10InvalidCharReplacement, writer);
writer.writeEndElement();
writer.writeEndElement();
} }
writeLink(writer, navigationLink, false);
writer.writeStartElement(METADATA, Constants.ATOM_ELEM_INLINE, NS_METADATA);
writeExpandedNavigationProperty(metadata, property, navigationLink,
childExpand, levels,
innerOptions == null ? null : innerOptions.getSelectOption(),
innerOptions == null ? null : innerOptions.getCountOption(),
innerOptions == null ? false : innerOptions.hasCountPath(),
innerOptions == null ? false : innerOptions.isRef(),
xml10InvalidCharReplacement, writer);
writer.writeEndElement();
writer.writeEndElement();
} else { } else {
writeLink(writer, getOrCreateLink(linked, propertyName)); writeLink(writer, getOrCreateLink(linked, propertyName));
} }
@ -676,7 +717,8 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
protected void writeExpandedNavigationProperty(final ServiceMetadata metadata, protected void writeExpandedNavigationProperty(final ServiceMetadata metadata,
final EdmNavigationProperty property, final Link navigationLink, final EdmNavigationProperty property, final Link navigationLink,
final ExpandOption innerExpand, final SelectOption innerSelect, final CountOption coutOption, final ExpandOption innerExpand, final Integer toDepth,
final SelectOption innerSelect, final CountOption coutOption,
final boolean writeNavigationCount, final boolean writeOnlyRef,final String xml10InvalidCharReplacement, final boolean writeNavigationCount, final boolean writeOnlyRef,final String xml10InvalidCharReplacement,
final XMLStreamWriter writer) throws XMLStreamException, SerializerException { final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
if (property.isCollection()) { if (property.isCollection()) {
@ -688,7 +730,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
if (coutOption != null && coutOption.getValue()) { if (coutOption != null && coutOption.getValue()) {
writeCount(navigationLink.getInlineEntitySet(), writer); writeCount(navigationLink.getInlineEntitySet(), writer);
} }
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand, writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand, toDepth,
innerSelect, xml10InvalidCharReplacement, writer, writeOnlyRef); innerSelect, xml10InvalidCharReplacement, writer, writeOnlyRef);
} }
writer.writeEndElement(); writer.writeEndElement();
@ -696,7 +738,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
} else { } else {
if (navigationLink != null && navigationLink.getInlineEntity() != null) { if (navigationLink != null && navigationLink.getInlineEntity() != null) {
writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null, writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null,
innerExpand, innerSelect, xml10InvalidCharReplacement, writer, false, writeOnlyRef); innerExpand, toDepth, innerSelect, xml10InvalidCharReplacement, writer, false, writeOnlyRef);
} }
} }
} }

View File

@ -65,6 +65,7 @@ import org.apache.olingo.server.api.uri.UriHelper;
import org.apache.olingo.server.api.uri.queryoption.CountOption; import org.apache.olingo.server.api.uri.queryoption.CountOption;
import org.apache.olingo.server.api.uri.queryoption.ExpandItem; import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.LevelsExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectItem; import org.apache.olingo.server.api.uri.queryoption.SelectItem;
import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.core.serializer.ExpandSelectMock; import org.apache.olingo.server.core.serializer.ExpandSelectMock;
@ -1357,6 +1358,53 @@ public class ODataJsonSerializerTest {
resultString); resultString);
} }
@Test
public void expandStarTwoLevels() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESTwoPrim");
final EdmEntityType entityType = edmEntitySet.getEntityType();
final EdmEntitySet innerEntitySet = entityContainer.getEntitySet("ESAllPrim");
final Entity entity = data.readAll(edmEntitySet).getEntities().get(1);
ExpandItem expandItem = Mockito.mock(ExpandItem.class);
Mockito.when(expandItem.isStar()).thenReturn(true);
LevelsExpandOption levels = Mockito.mock(LevelsExpandOption.class);
Mockito.when(levels.getValue()).thenReturn(2);
Mockito.when(expandItem.getLevelsOption()).thenReturn(levels);
final SelectOption select = ExpandSelectMock.mockSelectOption(Collections.singletonList(
ExpandSelectMock.mockSelectItem(innerEntitySet, "PropertyInt32")));
final ExpandOption expand = ExpandSelectMock.mockExpandOption(Collections.singletonList(expandItem));
final String resultString = IOUtils.toString(serializer
.entity(metadata, entityType, entity,
EntitySerializerOptions.with()
.contextURL(ContextURL.with().entitySet(edmEntitySet)
.selectList(helper.buildContextURLSelectList(entityType, expand, select))
.suffix(Suffix.ENTITY).build())
.expand(expand)
.build()).getContent());
Assert.assertEquals("{\"@odata.context\":\"$metadata#ESTwoPrim/$entity\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\","
+ "\"NavPropertyETAllPrimOne\":null,"
+ "\"NavPropertyETAllPrimMany\":["
+ "{\"PropertyInt16\":-32768,\"PropertyString\":\"Second Resource - negative values\","
+ "\"PropertyBoolean\":false,\"PropertyByte\":0,\"PropertySByte\":-128,\"PropertyInt32\":-2147483648,"
+ "\"PropertyInt64\":-9223372036854775808,\"PropertySingle\":-1.79E8,\"PropertyDouble\":-179000.0,"
+ "\"PropertyDecimal\":-34,\"PropertyBinary\":\"ASNFZ4mrze8=\",\"PropertyDate\":\"2015-11-05\","
+ "\"PropertyDateTimeOffset\":\"2005-12-03T07:17:08Z\",\"PropertyDuration\":\"PT9S\","
+ "\"PropertyGuid\":\"76543201-23ab-cdef-0123-456789dddfff\",\"PropertyTimeOfDay\":\"23:49:14\","
+ "\"NavPropertyETTwoPrimOne\":null,\"NavPropertyETTwoPrimMany\":[]},"
+ "{\"PropertyInt16\":0,\"PropertyString\":\"\",\"PropertyBoolean\":false,\"PropertyByte\":0,"
+ "\"PropertySByte\":0,\"PropertyInt32\":0,\"PropertyInt64\":0,\"PropertySingle\":0.0,"
+ "\"PropertyDouble\":0.0,\"PropertyDecimal\":0,\"PropertyBinary\":\"\","
+ "\"PropertyDate\":\"1970-01-01\",\"PropertyDateTimeOffset\":\"2005-12-03T00:00:00Z\","
+ "\"PropertyDuration\":\"PT0S\",\"PropertyGuid\":\"76543201-23ab-cdef-0123-456789cccddd\","
+ "\"PropertyTimeOfDay\":\"00:01:01\",\"NavPropertyETTwoPrimOne\":null,"
+ "\"NavPropertyETTwoPrimMany\":["
+ "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"},"
+ "{\"PropertyInt16\":-32766,\"PropertyString\":null},"
+ "{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"}]}]}",
resultString);
}
@Test @Test
public void primitiveProperty() throws Exception { public void primitiveProperty() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim"); final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");