OLINGO-811: implementing the =nav/ and =nav/
This commit is contained in:
parent
3786699f01
commit
5dee97f762
|
@ -37,7 +37,6 @@ import org.apache.olingo.client.api.domain.ClientEntity;
|
|||
import org.apache.olingo.client.api.domain.ClientEntitySet;
|
||||
import org.apache.olingo.client.api.uri.QueryOption;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ExpandWithSystemQueryOptionsITCase extends AbstractParamTecSvcITCase {
|
||||
|
@ -209,8 +208,7 @@ public class ExpandWithSystemQueryOptionsITCase extends AbstractParamTecSvcITCas
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Server do not support navigation property count annotations")
|
||||
public void count() {
|
||||
public void count() throws Exception{
|
||||
final ODataClient client = getEdmEnabledClient();
|
||||
Map<QueryOption, Object> options = new EnumMap<QueryOption, Object>(QueryOption.class);
|
||||
options.put(QueryOption.SELECT, "PropertyInt16");
|
||||
|
@ -220,6 +218,42 @@ public class ExpandWithSystemQueryOptionsITCase extends AbstractParamTecSvcITCas
|
|||
client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_TWO_KEY_NAV).expandWithOptions(
|
||||
NAV_PROPERTY_ET_TWO_KEY_NAV_MANY, options).addQueryOption(QueryOption.SELECT,
|
||||
"PropertyInt16,PropertyString").build();
|
||||
|
||||
final ODataRetrieveResponse<ClientEntitySet> response =
|
||||
client.getRetrieveRequestFactory().getEntitySetRequest(uri).execute();
|
||||
|
||||
final List<ClientEntity> entities = response.getBody().getEntities();
|
||||
assertEquals(4, entities.size());
|
||||
|
||||
for (final ClientEntity entity : entities) {
|
||||
final Object propInt16 = entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue();
|
||||
final Object propString = entity.getProperty(PROPERTY_STRING).getPrimitiveValue().toValue();
|
||||
final ClientEntitySet entitySet =
|
||||
entity.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY).asInlineEntitySet().getEntitySet();
|
||||
|
||||
if ((propInt16.equals(1) ||propInt16.equals((short)1)) && propString.equals("1")) {
|
||||
assertEquals(Integer.valueOf(2), entitySet.getCount());
|
||||
} else if ((propInt16.equals(1) ||propInt16.equals((short)1)) && propString.equals("2")) {
|
||||
assertEquals(Integer.valueOf(1), entitySet.getCount());
|
||||
} else if ((propInt16.equals(2) ||propInt16.equals((short)2)) && propString.equals("1")) {
|
||||
assertEquals(Integer.valueOf(1), entitySet.getCount());
|
||||
} else if ((propInt16.equals(3) ||propInt16.equals((short)3)) && propString.equals("1")) {
|
||||
assertEquals(Integer.valueOf(0), entitySet.getCount());
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countOnly() throws Exception {
|
||||
final ODataClient client = getEdmEnabledClient();
|
||||
Map<QueryOption, Object> options = new EnumMap<QueryOption, Object>(QueryOption.class);
|
||||
|
||||
final URI uri =
|
||||
client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_TWO_KEY_NAV).expandWithOptions(
|
||||
NAV_PROPERTY_ET_TWO_KEY_NAV_MANY, false, true, options).addQueryOption(QueryOption.SELECT,
|
||||
"PropertyInt16,PropertyString").build();
|
||||
final ODataRetrieveResponse<ClientEntitySet> response =
|
||||
client.getRetrieveRequestFactory().getEntitySetRequest(uri).execute();
|
||||
|
||||
|
@ -232,20 +266,63 @@ public class ExpandWithSystemQueryOptionsITCase extends AbstractParamTecSvcITCas
|
|||
final ClientEntitySet entitySet =
|
||||
entity.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY).asInlineEntitySet().getEntitySet();
|
||||
|
||||
if (propInt16.equals(1) && propString.equals("1")) {
|
||||
if ((propInt16.equals(1) ||propInt16.equals((short)1)) && propString.equals("1")) {
|
||||
assertEquals(Integer.valueOf(2), entitySet.getCount());
|
||||
} else if (propInt16.equals(1) && propString.equals("2")) {
|
||||
assertEquals(Integer.valueOf(2), entitySet.getCount());
|
||||
} else if (propInt16.equals(2) && propString.equals("1")) {
|
||||
assertEquals(Integer.valueOf(2), entitySet.getCount());
|
||||
} else if (propInt16.equals(3) && propString.equals("1")) {
|
||||
} else if ((propInt16.equals(1) ||propInt16.equals((short)1)) && propString.equals("2")) {
|
||||
assertEquals(Integer.valueOf(1), entitySet.getCount());
|
||||
} else if ((propInt16.equals(2) ||propInt16.equals((short)2)) && propString.equals("1")) {
|
||||
assertEquals(Integer.valueOf(1), entitySet.getCount());
|
||||
} else if ((propInt16.equals(3) ||propInt16.equals((short)3)) && propString.equals("1")) {
|
||||
assertEquals(Integer.valueOf(0), entitySet.getCount());
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reference() throws Exception {
|
||||
final ODataClient client = getEdmEnabledClient();
|
||||
Map<QueryOption, Object> options = new EnumMap<QueryOption, Object>(QueryOption.class);
|
||||
|
||||
final URI uri =
|
||||
client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_TWO_KEY_NAV).expandWithOptions(
|
||||
NAV_PROPERTY_ET_TWO_KEY_NAV_MANY, true, false, options).addQueryOption(QueryOption.SELECT,
|
||||
"PropertyInt16,PropertyString").build();
|
||||
final ODataRetrieveResponse<ClientEntitySet> response =
|
||||
client.getRetrieveRequestFactory().getEntitySetRequest(uri).execute();
|
||||
|
||||
final List<ClientEntity> entities = response.getBody().getEntities();
|
||||
assertEquals(4, entities.size());
|
||||
|
||||
for (final ClientEntity entity : entities) {
|
||||
final Object propInt16 = entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue();
|
||||
final Object propString = entity.getProperty(PROPERTY_STRING).getPrimitiveValue().toValue();
|
||||
final ClientEntitySet entitySet =
|
||||
entity.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY).asInlineEntitySet().getEntitySet();
|
||||
|
||||
if ((propInt16.equals(1) ||propInt16.equals((short)1)) && propString.equals("1")) {
|
||||
assertEquals(2, entitySet.getEntities().size());
|
||||
assertEquals("ESTwoKeyNav(PropertyInt16=1,PropertyString='1')",
|
||||
entitySet.getEntities().get(0).getId().toString());
|
||||
assertEquals("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
|
||||
entitySet.getEntities().get(1).getId().toString());
|
||||
} else if ((propInt16.equals(1) ||propInt16.equals((short)1)) && propString.equals("2")) {
|
||||
assertEquals(1, entitySet.getEntities().size());
|
||||
assertEquals("ESTwoKeyNav(PropertyInt16=1,PropertyString='1')",
|
||||
entitySet.getEntities().get(0).getId().toString());
|
||||
} else if ((propInt16.equals(2) ||propInt16.equals((short)2)) && propString.equals("1")) {
|
||||
assertEquals(1, entitySet.getEntities().size());
|
||||
assertEquals("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
|
||||
entitySet.getEntities().get(0).getId().toString());
|
||||
} else if ((propInt16.equals(3) ||propInt16.equals((short)3)) && propString.equals("1")) {
|
||||
assertEquals(0, entitySet.getEntities().size());
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleEntityWithExpand() {
|
||||
/* A single entity request will be dispatched to a different processor method than entity set request */
|
||||
|
|
|
@ -350,6 +350,21 @@ public interface URIBuilder {
|
|||
*/
|
||||
URIBuilder expandWithOptions(String expandItem, Map<QueryOption, Object> options);
|
||||
|
||||
/**
|
||||
* The set of expanded entities can be refined through the application of expand options, expressed as a
|
||||
* semicolon-separated list of system query options, enclosed in parentheses, see [OData-URL].
|
||||
*
|
||||
* @param expandItem item to be expanded.
|
||||
* @param pathRef include the /$ref at the end of the $expand item's path;if true pathCount MUST be false
|
||||
* @param pathCount include /$count at the end of the $expand item's path;if true pathRef MUST be false
|
||||
* @param options System query options. Allowed query options are: $filter, $select, $orderby, $skip, $top, $count,
|
||||
* $search, $expand, and $levels.
|
||||
* @return current URIBuilder instance.
|
||||
* @see org.apache.olingo.client.api.uri.QueryOption#EXPAND
|
||||
*/
|
||||
URIBuilder expandWithOptions(String expandItem, boolean pathRef,
|
||||
boolean pathCount, Map<QueryOption, Object> options);
|
||||
|
||||
/**
|
||||
* Properties of related entities can be specified by including the $select query option within the $expand.
|
||||
* <br />
|
||||
|
|
|
@ -94,6 +94,12 @@ public class JsonDeserializer implements ODataDeserializer {
|
|||
final ObjectCodec codec, final Link link) throws IOException {
|
||||
|
||||
final String entityNamePrefix = name.substring(0, name.indexOf(suffix));
|
||||
|
||||
Integer count = null;
|
||||
if (tree.hasNonNull(entityNamePrefix+Constants.JSON_COUNT)) {
|
||||
count = tree.get(entityNamePrefix+Constants.JSON_COUNT).asInt();
|
||||
}
|
||||
|
||||
if (tree.has(entityNamePrefix)) {
|
||||
final JsonNode inline = tree.path(entityNamePrefix);
|
||||
JsonEntityDeserializer entityDeserializer = new JsonEntityDeserializer(serverMode);
|
||||
|
@ -106,6 +112,9 @@ public class JsonDeserializer implements ODataDeserializer {
|
|||
link.setType(Constants.ENTITY_SET_NAVIGATION_LINK_TYPE);
|
||||
|
||||
final EntityCollection entitySet = new EntityCollection();
|
||||
if (count != null) {
|
||||
entitySet.setCount(count);
|
||||
}
|
||||
for (final Iterator<JsonNode> entries = inline.elements(); entries.hasNext();) {
|
||||
entitySet.getEntities().add(entityDeserializer.doDeserialize(entries.next().traverse(codec)).getPayload());
|
||||
}
|
||||
|
@ -247,6 +256,11 @@ public class JsonDeserializer implements ODataDeserializer {
|
|||
}
|
||||
} else if (type == null && field.getKey().endsWith(getJSONAnnotation(Constants.JSON_TYPE))) {
|
||||
type = field.getValue().asText();
|
||||
} else if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_COUNT))) {
|
||||
final Property property = new Property();
|
||||
property.setName(field.getKey());
|
||||
property.setValue(ValueType.PRIMITIVE, Integer.parseInt(field.getValue().asText()));
|
||||
properties.add(property);
|
||||
} else if (annotation == null && customAnnotation.matches() && !"odata".equals(customAnnotation.group(2))) {
|
||||
annotation = new Annotation();
|
||||
annotation.setTerm(customAnnotation.group(2) + "." + customAnnotation.group(3));
|
||||
|
|
|
@ -23,7 +23,9 @@ import java.net.URI;
|
|||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.olingo.client.api.EdmEnabledODataClient;
|
||||
|
@ -565,23 +567,50 @@ public class ODataBinderImpl implements ODataBinder {
|
|||
return type;
|
||||
}
|
||||
|
||||
private ClientLink createLinkFromNavigationProperty(final Property property, final String propertyTypeName) {
|
||||
private ClientLink createLinkFromNavigationProperty(final Property property, final String propertyTypeName,
|
||||
final Integer count) {
|
||||
if (property.isCollection()) {
|
||||
EntityCollection inlineEntitySet = new EntityCollection();
|
||||
for (final Object inlined : property.asCollection()) {
|
||||
Entity inlineEntity = new Entity();
|
||||
inlineEntity.setType(propertyTypeName);
|
||||
inlineEntity.getProperties().addAll(((ComplexValue) inlined).getValue());
|
||||
copyAnnotations(inlineEntity, (ComplexValue) inlined);
|
||||
inlineEntitySet.getEntities().add(inlineEntity);
|
||||
}
|
||||
if (count != null) {
|
||||
inlineEntitySet.setCount(count);
|
||||
}
|
||||
return createODataInlineEntitySet(inlineEntitySet, null, property.getName(), null);
|
||||
} else {
|
||||
Entity inlineEntity = new Entity();
|
||||
inlineEntity.setType(propertyTypeName);
|
||||
inlineEntity.getProperties().addAll(property.asComplex().getValue());
|
||||
copyAnnotations(inlineEntity, property.asComplex());
|
||||
return createODataInlineEntity(inlineEntity, null, property.getName(), null);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyAnnotations(Entity inlineEntity, ComplexValue complex) {
|
||||
for (Annotation annotation:complex.getAnnotations()) {
|
||||
if (annotation.getTerm().equals(Constants.JSON_TYPE.substring(1))){
|
||||
inlineEntity.setType((String)annotation.asPrimitive());
|
||||
} else if (annotation.getTerm().equals(Constants.JSON_ID.substring(1))){
|
||||
inlineEntity.setId(URI.create((String)annotation.asPrimitive()));
|
||||
} else if (annotation.getTerm().equals(Constants.JSON_ETAG.substring(1))){
|
||||
inlineEntity.setETag((String)annotation.asPrimitive());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ClientLink createLinkFromEmptyNavigationProperty(final String propertyName,
|
||||
final Integer count) {
|
||||
EntityCollection inlineEntitySet = new EntityCollection();
|
||||
if (count != null) {
|
||||
inlineEntitySet.setCount(count);
|
||||
}
|
||||
return createODataInlineEntitySet(inlineEntitySet, null, propertyName, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientEntity getODataEntity(final ResWrap<Entity> resource) {
|
||||
|
@ -650,21 +679,45 @@ public class ODataBinderImpl implements ODataBinder {
|
|||
entity.setMediaETag(resource.getPayload().getMediaETag());
|
||||
}
|
||||
|
||||
Map<String, Integer> countMap = new HashMap<String, Integer>();
|
||||
for (final Property property : resource.getPayload().getProperties()) {
|
||||
EdmType propertyType = null;
|
||||
if (edmType instanceof EdmEntityType) {
|
||||
final EdmElement edmProperty = ((EdmEntityType) edmType).getProperty(property.getName());
|
||||
EdmElement edmProperty = ((EdmEntityType) edmType).getProperty(property.getName());
|
||||
if (edmProperty != null) {
|
||||
propertyType = edmProperty.getType();
|
||||
if (edmProperty instanceof EdmNavigationProperty && !property.isNull()) {
|
||||
final String propertyTypeName = propertyType.getFullQualifiedName().getFullQualifiedNameAsString();
|
||||
entity.addLink(createLinkFromNavigationProperty(property, propertyTypeName));
|
||||
entity.addLink(createLinkFromNavigationProperty(property, propertyTypeName,
|
||||
countMap.remove(property.getName())));
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
int idx = property.getName().indexOf(Constants.JSON_COUNT);
|
||||
if (idx != -1) {
|
||||
String navigationName = property.getName().substring(0, idx);
|
||||
edmProperty = ((EdmEntityType) edmType).getProperty(navigationName);
|
||||
if (edmProperty != null) {
|
||||
if (edmProperty instanceof EdmNavigationProperty) {
|
||||
ClientLink link = entity.getNavigationLink(navigationName);
|
||||
if (link == null) {
|
||||
countMap.put(navigationName, (Integer)property.getValue());
|
||||
} else {
|
||||
link.asInlineEntitySet().getEntitySet().setCount((Integer)property.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
add(entity, getODataProperty(propertyType, property));
|
||||
}
|
||||
|
||||
if (!countMap.isEmpty()) {
|
||||
for (String name:countMap.keySet()) {
|
||||
entity.addLink(createLinkFromEmptyNavigationProperty(name, countMap.get(name)));
|
||||
}
|
||||
}
|
||||
|
||||
entity.setId(resource.getPayload().getId());
|
||||
odataAnnotations(resource.getPayload(), entity);
|
||||
|
|
|
@ -446,13 +446,20 @@ public class URIBuilderImpl implements URIBuilder {
|
|||
|
||||
@Override
|
||||
public URIBuilder expandWithOptions(final String expandItem, final Map<QueryOption, Object> options) {
|
||||
return expandWithOptions(expandItem, false, false, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URIBuilder expandWithOptions(String expandItem, boolean pathRef,
|
||||
boolean pathCount, Map<QueryOption, Object> options) {
|
||||
final Map<String, Object> _options = new LinkedHashMap<String, Object>();
|
||||
for (Map.Entry<QueryOption, Object> entry : options.entrySet()) {
|
||||
_options.put("$" + entry.getKey().toString(), entry.getValue());
|
||||
}
|
||||
return expand(expandItem + buildMultiKeySegment(_options, false, ';'));
|
||||
String path = pathRef?"/$ref":pathCount?"/$count":StringUtils.EMPTY;
|
||||
return expand(expandItem + buildMultiKeySegment(_options, false, ';')+path);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public URIBuilder expandWithSelect(final String expandItem, final String... selectItems) {
|
||||
return expand(expandItem + "($select=" + StringUtils.join(selectItems, ",") + ")");
|
||||
|
|
|
@ -87,6 +87,21 @@ public class URIBuilderTest extends AbstractTest {
|
|||
assertEquals(new org.apache.http.client.utils.URIBuilder(SERVICE_ROOT + "/Products(5)").
|
||||
addParameter("$expand", "ProductDetails($expand=ProductInfo;$select=Price),Orders,Customers").build(), uri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expandWithOptionsCount() throws URISyntaxException {
|
||||
final URI uri = client.newURIBuilder(SERVICE_ROOT).appendEntitySetSegment("Products").appendKeySegment(5).
|
||||
expandWithOptions("ProductDetails", false, true, new LinkedHashMap<QueryOption, Object>() {
|
||||
private static final long serialVersionUID = 3109256773218160485L;
|
||||
{
|
||||
put(QueryOption.EXPAND, "ProductInfo");
|
||||
put(QueryOption.SELECT, "Price");
|
||||
}
|
||||
}).expand("Orders", "Customers").build();
|
||||
assertEquals(new org.apache.http.client.utils.URIBuilder(SERVICE_ROOT + "/Products(5)").
|
||||
addParameter("$expand", "ProductDetails($expand=ProductInfo;$select=Price)/$count,Orders,Customers")
|
||||
.build(), uri);
|
||||
}
|
||||
|
||||
public void expandWithLevels() throws URISyntaxException {
|
||||
final URI uri = client.newURIBuilder(SERVICE_ROOT).appendEntitySetSegment("Products").appendKeySegment(1).
|
||||
|
|
|
@ -85,10 +85,16 @@ public interface ExpandItem {
|
|||
|
||||
/**
|
||||
* @return A $ref is used within $expand.
|
||||
* For example: ...?$expand=$ref
|
||||
* For example: ...?$expand=navigation/$ref
|
||||
*/
|
||||
boolean isRef();
|
||||
|
||||
/**
|
||||
* @return A $count is used within $expand.
|
||||
* For example: ...?$expand=navigation/$count
|
||||
*/
|
||||
boolean hasCountPath();
|
||||
|
||||
/**
|
||||
* @return Before resource path segments which should be expanded a type filter may be used.
|
||||
* For example: ...persons?$expand=namespace.managertype/team
|
||||
|
|
|
@ -26,10 +26,10 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import org.apache.olingo.commons.api.Constants;
|
||||
import org.apache.olingo.commons.api.data.AbstractEntityCollection;
|
||||
import org.apache.olingo.commons.api.data.ComplexValue;
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.AbstractEntityCollection;
|
||||
import org.apache.olingo.commons.api.data.EntityIterator;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
import org.apache.olingo.commons.api.data.Linked;
|
||||
|
@ -60,11 +60,12 @@ import org.apache.olingo.server.api.serializer.SerializerException;
|
|||
import org.apache.olingo.server.api.serializer.SerializerResult;
|
||||
import org.apache.olingo.server.api.serializer.SerializerStreamResult;
|
||||
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.ExpandItem;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
import org.apache.olingo.server.core.serializer.AbstractODataSerializer;
|
||||
import org.apache.olingo.server.core.ODataWritableContent;
|
||||
import org.apache.olingo.server.core.serializer.AbstractODataSerializer;
|
||||
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.ContentTypeHelper;
|
||||
|
@ -402,30 +403,54 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
writeExpandedNavigationProperty(metadata, property, navigationLink,
|
||||
innerOptions == null ? null : innerOptions.getExpandOption(),
|
||||
innerOptions == null ? null : innerOptions.getSelectOption(), json);
|
||||
innerOptions == null ? null : innerOptions.getSelectOption(),
|
||||
innerOptions == null ? null : innerOptions.getCountOption(),
|
||||
innerOptions == null ? false : innerOptions.hasCountPath(),
|
||||
innerOptions == null ? false : innerOptions.isRef(),
|
||||
json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeExpandedNavigationProperty(final ServiceMetadata metadata, final EdmNavigationProperty property,
|
||||
final Link navigationLink, final ExpandOption innerExpand, final SelectOption innerSelect,
|
||||
|
||||
protected void writeExpandedNavigationProperty(
|
||||
final ServiceMetadata metadata, final EdmNavigationProperty property,
|
||||
final Link navigationLink, final ExpandOption innerExpand,
|
||||
final SelectOption innerSelect, final CountOption innerCount,
|
||||
final boolean writeOnlyCount, final boolean writeOnlyRef,
|
||||
final JsonGenerator json) throws IOException, SerializerException {
|
||||
json.writeFieldName(property.getName());
|
||||
|
||||
if (property.isCollection()) {
|
||||
if (navigationLink == null || navigationLink.getInlineEntitySet() == null) {
|
||||
json.writeStartArray();
|
||||
json.writeEndArray();
|
||||
} else {
|
||||
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
|
||||
innerSelect, false, json);
|
||||
if (writeOnlyCount) {
|
||||
if (navigationLink == null || navigationLink.getInlineEntitySet() == null) {
|
||||
writeInlineCount(property.getName(), 0, json);
|
||||
} else {
|
||||
writeInlineCount(property.getName(), navigationLink.getInlineEntitySet().getCount(), json);
|
||||
}
|
||||
} else {
|
||||
if (navigationLink == null || navigationLink.getInlineEntitySet() == null) {
|
||||
if (innerCount != null && innerCount.getValue()) {
|
||||
writeInlineCount(property.getName(), 0, json);
|
||||
}
|
||||
json.writeFieldName(property.getName());
|
||||
json.writeStartArray();
|
||||
json.writeEndArray();
|
||||
} else {
|
||||
if (innerCount != null && innerCount.getValue()) {
|
||||
writeInlineCount(property.getName(), navigationLink.getInlineEntitySet().getCount(), json);
|
||||
}
|
||||
json.writeFieldName(property.getName());
|
||||
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
|
||||
innerSelect, writeOnlyRef, json);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
json.writeFieldName(property.getName());
|
||||
if (navigationLink == null || navigationLink.getInlineEntity() == null) {
|
||||
json.writeNull();
|
||||
} else {
|
||||
writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null,
|
||||
innerExpand, innerSelect, false, json);
|
||||
innerExpand, innerSelect, writeOnlyRef, json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -852,6 +877,18 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
void writeInlineCount(final String propertyName,
|
||||
final Integer count, final JsonGenerator json)
|
||||
throws IOException {
|
||||
if (count != null) {
|
||||
if (isIEEE754Compatible) {
|
||||
json.writeStringField(propertyName+Constants.JSON_COUNT, String.valueOf(count));
|
||||
} else {
|
||||
json.writeNumberField(propertyName+Constants.JSON_COUNT, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writeNextLink(final AbstractEntityCollection entitySet, final JsonGenerator json) throws IOException {
|
||||
if (entitySet.getNext() != null) {
|
||||
json.writeStringField(Constants.JSON_NEXT_LINK, entitySet.getNext().toASCIIString());
|
||||
|
|
|
@ -66,6 +66,7 @@ import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
|
|||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.serializer.SerializerResult;
|
||||
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.ExpandItem;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
|
@ -254,11 +255,12 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
writeNextLink(entitySet, writer);
|
||||
}
|
||||
|
||||
boolean writeOnlyRef = (options != null && options.getWriteOnlyReferences());
|
||||
if (options == null) {
|
||||
writeEntitySet(metadata, entityType, entitySet, null, null, null, writer);
|
||||
writeEntitySet(metadata, entityType, entitySet, null, null, null, writer, writeOnlyRef);
|
||||
} else {
|
||||
writeEntitySet(metadata, entityType, entitySet,
|
||||
options.getExpand(), options.getSelect(), options.xml10InvalidCharReplacement(), writer);
|
||||
options.getExpand(), options.getSelect(), options.xml10InvalidCharReplacement(), writer, writeOnlyRef);
|
||||
}
|
||||
|
||||
writer.writeEndElement();
|
||||
|
@ -310,11 +312,12 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
writeCount(entitySet, writer);
|
||||
}
|
||||
|
||||
boolean writeOnlyRef = (options != null && options.getWriteOnlyReferences());
|
||||
if (options == null) {
|
||||
writeEntitySet(metadata, entityType, entitySet, null, null, null, writer);
|
||||
writeEntitySet(metadata, entityType, entitySet, null, null, null, writer, writeOnlyRef);
|
||||
} else {
|
||||
writeEntitySet(metadata, entityType, entitySet,
|
||||
options.getExpand(), options.getSelect(), options.xml10InvalidCharReplacement(), writer);
|
||||
options.getExpand(), options.getSelect(), options.xml10InvalidCharReplacement(), writer, writeOnlyRef);
|
||||
}
|
||||
|
||||
writer.writeEndElement();
|
||||
|
@ -355,7 +358,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
options == null ? null : options.getExpand(),
|
||||
options == null ? null : options.getSelect(),
|
||||
options == null ? null : options.xml10InvalidCharReplacement(),
|
||||
writer, true);
|
||||
writer, true, false);
|
||||
writer.writeEndDocument();
|
||||
|
||||
writer.flush();
|
||||
|
@ -395,19 +398,24 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
|
||||
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final AbstractEntityCollection entitySet, final ExpandOption expand, final SelectOption select,
|
||||
final String xml10InvalidCharReplacement,final XMLStreamWriter writer)
|
||||
final String xml10InvalidCharReplacement,final XMLStreamWriter writer, final boolean writeOnlyRef)
|
||||
throws XMLStreamException, SerializerException {
|
||||
for (final Entity entity : entitySet) {
|
||||
writeEntity(metadata, entityType, entity, null, expand, select, xml10InvalidCharReplacement, writer, false);
|
||||
writeEntity(metadata, entityType, entity, null, expand, select,
|
||||
xml10InvalidCharReplacement, writer, false, writeOnlyRef);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Entity entity, final ContextURL contextURL, final ExpandOption expand,
|
||||
final SelectOption select, final String xml10InvalidCharReplacement,
|
||||
final XMLStreamWriter writer, final boolean top)
|
||||
final XMLStreamWriter writer, final boolean top, final boolean writeOnlyRef)
|
||||
throws XMLStreamException, SerializerException {
|
||||
|
||||
if (writeOnlyRef) {
|
||||
writeReference(entity, contextURL, writer, top);
|
||||
return;
|
||||
}
|
||||
writer.writeStartElement(ATOM, Constants.ATOM_ELEM_ENTRY, NS_ATOM);
|
||||
if (top) {
|
||||
writer.writeNamespace(ATOM, NS_ATOM);
|
||||
|
@ -591,7 +599,10 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
writeExpandedNavigationProperty(metadata, property, navigationLink,
|
||||
innerOptions == null ? null : innerOptions.getExpandOption(),
|
||||
innerOptions == null ? null : innerOptions.getSelectOption(),
|
||||
xml10InvalidCharReplacement, writer);
|
||||
innerOptions == null ? null : innerOptions.getCountOption(),
|
||||
innerOptions == null ? false : innerOptions.hasCountPath(),
|
||||
innerOptions == null ? false : innerOptions.isRef(),
|
||||
xml10InvalidCharReplacement, writer);
|
||||
writer.writeEndElement();
|
||||
writer.writeEndElement();
|
||||
}
|
||||
|
@ -650,19 +661,27 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
|
||||
protected void writeExpandedNavigationProperty(final ServiceMetadata metadata,
|
||||
final EdmNavigationProperty property, final Link navigationLink,
|
||||
final ExpandOption innerExpand, final SelectOption innerSelect, final String xml10InvalidCharReplacement,
|
||||
final ExpandOption innerExpand, final SelectOption innerSelect, final CountOption coutOption,
|
||||
final boolean writeNavigationCount, final boolean writeOnlyRef,final String xml10InvalidCharReplacement,
|
||||
final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
|
||||
if (property.isCollection()) {
|
||||
if (navigationLink != null && navigationLink.getInlineEntitySet() != null) {
|
||||
writer.writeStartElement(ATOM, Constants.ATOM_ELEM_FEED, NS_ATOM);
|
||||
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
|
||||
innerSelect, xml10InvalidCharReplacement, writer);
|
||||
if (writeNavigationCount) {
|
||||
writeCount(navigationLink.getInlineEntitySet(), writer);
|
||||
} else {
|
||||
if (coutOption != null && coutOption.getValue()) {
|
||||
writeCount(navigationLink.getInlineEntitySet(), writer);
|
||||
}
|
||||
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
|
||||
innerSelect, xml10InvalidCharReplacement, writer, writeOnlyRef);
|
||||
}
|
||||
writer.writeEndElement();
|
||||
}
|
||||
} else {
|
||||
if (navigationLink != null && navigationLink.getInlineEntity() != null) {
|
||||
writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null,
|
||||
innerExpand, innerSelect, xml10InvalidCharReplacement, writer, false);
|
||||
innerExpand, innerSelect, xml10InvalidCharReplacement, writer, false, writeOnlyRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1173,7 +1192,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
private void writeCount(final AbstractEntityCollection entitySet, final XMLStreamWriter writer)
|
||||
throws XMLStreamException {
|
||||
writer.writeStartElement(METADATA, Constants.ATOM_ELEM_COUNT, NS_METADATA);
|
||||
writer.writeCharacters(String.valueOf(entitySet.getCount()));
|
||||
writer.writeCharacters(String.valueOf(entitySet.getCount()==null?0:entitySet.getCount()));
|
||||
writer.writeEndElement();
|
||||
}
|
||||
|
||||
|
|
|
@ -160,10 +160,12 @@ public class ExpandParser {
|
|||
if (hasSlash || tokenizer.next(TokenKind.SLASH)) {
|
||||
if (tokenizer.next(TokenKind.REF)) {
|
||||
resource.addResourcePart(new UriResourceRefImpl());
|
||||
item.setIsRef(true);
|
||||
parseOptions(tokenizer, newReferencedType, newReferencedIsCollection, item, true, false);
|
||||
} else {
|
||||
ParserHelper.requireNext(tokenizer, TokenKind.COUNT);
|
||||
resource.addResourcePart(new UriResourceCountImpl());
|
||||
item.setCountPath(true);
|
||||
parseOptions(tokenizer, newReferencedType, newReferencedIsCollection, item, false, true);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -51,6 +51,7 @@ public class ExpandItemImpl implements ExpandItem {
|
|||
private boolean isStar;
|
||||
|
||||
private boolean isRef;
|
||||
private boolean hasCountPath;
|
||||
private EdmType startTypeFilter;
|
||||
|
||||
public ExpandItemImpl setSystemQueryOption(final SystemQueryOption sysItem) {
|
||||
|
@ -187,4 +188,13 @@ public class ExpandItemImpl implements ExpandItem {
|
|||
this.startTypeFilter = startTypeFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCountPath() {
|
||||
return this.hasCountPath;
|
||||
}
|
||||
|
||||
public void setCountPath(boolean value) {
|
||||
this.hasCountPath = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -439,7 +439,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
final SelectOption select = uriInfo.getSelectOption();
|
||||
|
||||
final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler();
|
||||
final Entity entitySerialization = expandHandler.transformEntityGraphToTree(entity, edmEntitySet, expand);
|
||||
final Entity entitySerialization = expandHandler.transformEntityGraphToTree(entity, edmEntitySet, expand, null);
|
||||
expandHandler.applyExpandQueryOptions(entitySerialization, edmEntitySet, expand, uriInfo,
|
||||
serviceMetadata.getEdm());
|
||||
|
||||
|
@ -515,7 +515,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler();
|
||||
final EntityCollection entitySetSerialization = expandHandler.transformEntitySetGraphToTree(entitySet,
|
||||
edmEntitySet,
|
||||
expand);
|
||||
expand, null);
|
||||
expandHandler.applyExpandQueryOptions(entitySetSerialization, edmEntitySet, expand, uriInfo,
|
||||
serviceMetadata.getEdm());
|
||||
final CountOption countOption = uriInfo.getCountOption();
|
||||
|
|
|
@ -96,11 +96,8 @@ public class ExpandSystemQueryOptionHandler {
|
|||
}
|
||||
} else {
|
||||
final List<UriResource> uriResourceParts = item.getResourcePath().getUriResourceParts();
|
||||
if (uriResourceParts.size() == 1 && uriResourceParts.get(0) instanceof UriResourceNavigation) {
|
||||
if (uriResourceParts.get(0) instanceof UriResourceNavigation) {
|
||||
navigationProperties.add(((UriResourceNavigation) uriResourceParts.get(0)).getProperty());
|
||||
} else {
|
||||
throw new ODataApplicationException("Not supported resource part in expand system query option",
|
||||
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,19 +143,22 @@ public class ExpandSystemQueryOptionHandler {
|
|||
}
|
||||
|
||||
public EntityCollection transformEntitySetGraphToTree(final EntityCollection entitySet,
|
||||
final EdmBindingTarget edmBindingTarget, final ExpandOption expand) throws ODataApplicationException {
|
||||
final EdmBindingTarget edmBindingTarget, final ExpandOption expand,
|
||||
final ExpandItem expandItem) throws ODataApplicationException {
|
||||
|
||||
final EntityCollection newEntitySet = newEntitySet(entitySet);
|
||||
|
||||
for (final Entity entity : entitySet.getEntities()) {
|
||||
newEntitySet.getEntities().add(transformEntityGraphToTree(entity, edmBindingTarget, expand));
|
||||
newEntitySet.getEntities().add(transformEntityGraphToTree(entity, edmBindingTarget, expand, expandItem));
|
||||
}
|
||||
if (expandItem != null && expandItem.hasCountPath()) {
|
||||
newEntitySet.setCount(entitySet.getEntities().size());
|
||||
}
|
||||
|
||||
return newEntitySet;
|
||||
}
|
||||
|
||||
public Entity transformEntityGraphToTree(final Entity entity, final EdmBindingTarget edmEntitySet,
|
||||
final ExpandOption expand) throws ODataApplicationException {
|
||||
final ExpandOption expand, final ExpandItem parentExpandItem) throws ODataApplicationException {
|
||||
final Entity newEntity = newEntity(entity);
|
||||
if (hasExpandItems(expand)) {
|
||||
final boolean expandAll = expandAll(expand);
|
||||
|
@ -173,16 +173,14 @@ public class ExpandSystemQueryOptionHandler {
|
|||
final EdmBindingTarget edmBindingTarget = edmEntitySet.getRelatedBindingTarget(propertyName);
|
||||
final Link newLink = newLink(link);
|
||||
newEntity.getNavigationLinks().add(newLink);
|
||||
final ExpandOption innerExpandOption = getInnerExpandOption(expand, propertyName);
|
||||
final ExpandItem expandItem = getInnerExpandItem(expand, propertyName);
|
||||
|
||||
if (edmNavigationProperty.isCollection()) {
|
||||
newLink.setInlineEntitySet(transformEntitySetGraphToTree(link.getInlineEntitySet(),
|
||||
edmBindingTarget,
|
||||
innerExpandOption));
|
||||
edmBindingTarget, expandItem.getExpandOption(), expandItem));
|
||||
} else {
|
||||
newLink.setInlineEntity(transformEntityGraphToTree(link.getInlineEntity(),
|
||||
edmBindingTarget,
|
||||
innerExpandOption));
|
||||
edmBindingTarget,expandItem.getExpandOption(), expandItem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -250,29 +248,24 @@ public class ExpandSystemQueryOptionHandler {
|
|||
Set<String> expanded = new HashSet<String>();
|
||||
for (final ExpandItem item : expandItems) {
|
||||
final List<UriResource> resourceParts = item.getResourcePath().getUriResourceParts();
|
||||
if (resourceParts.size() == 1) {
|
||||
final UriResource resource = resourceParts.get(0);
|
||||
if (resource instanceof UriResourceNavigation) {
|
||||
expanded.add(((UriResourceNavigation) resource).getProperty().getName());
|
||||
}
|
||||
} else {
|
||||
throw new ODataApplicationException("Expand is not supported within complex properties.",
|
||||
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
|
||||
final UriResource resource = resourceParts.get(0);
|
||||
if (resource instanceof UriResourceNavigation) {
|
||||
expanded.add(((UriResourceNavigation) resource).getProperty().getName());
|
||||
}
|
||||
}
|
||||
return expanded;
|
||||
}
|
||||
|
||||
private ExpandOption getInnerExpandOption(final ExpandOption expand, final String propertyName) {
|
||||
private ExpandItem getInnerExpandItem(final ExpandOption expand, final String propertyName) {
|
||||
for (final ExpandItem item : expand.getExpandItems()) {
|
||||
if(item.isStar()) {
|
||||
return item.getExpandOption();
|
||||
return item;
|
||||
}
|
||||
|
||||
final UriResource resource = item.getResourcePath().getUriResourceParts().get(0);
|
||||
if (resource instanceof UriResourceNavigation
|
||||
&& propertyName.equals(((UriResourceNavigation) resource).getProperty().getName())) {
|
||||
return item.getExpandOption();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue