[OLINGO-754] IEEE754Compatible support for ODataJsonSerializer

This commit is contained in:
Christian Holzer 2015-06-02 15:52:57 +02:00
parent 5501e8e331
commit 974abcb40f
15 changed files with 587 additions and 115 deletions

View File

@ -75,7 +75,9 @@ public final class ContentType {
public static final ContentType MULTIPART_FORM_DATA = new ContentType(MULTIPART, "form-data", null); public static final ContentType MULTIPART_FORM_DATA = new ContentType(MULTIPART, "form-data", null);
public static final String PARAMETER_CHARSET_UTF8 = "charset=utf-8"; public static final String PARAMETER_CHARSET_UTF8 = "charset=utf-8";
public static final String PARAMETER_IEEE754_COMPATIBLE = "IEEE754Compatible=true";
public static final String PARAMETER_IEEE754_COMPATIBLE_FALSE = "IEEE754Compatible=false";
private final String type; private final String type;
private final String subtype; private final String subtype;
private final Map<String, String> parameters; private final Map<String, String> parameters;

View File

@ -28,7 +28,8 @@ public class ComplexSerializerOptions {
private ContextURL contextURL; private ContextURL contextURL;
private ExpandOption expand; private ExpandOption expand;
private SelectOption select; private SelectOption select;
private boolean isIEEE754Compatible;
/** Gets the {@link ContextURL}. */ /** Gets the {@link ContextURL}. */
public ContextURL getContextURL() { public ContextURL getContextURL() {
return contextURL; return contextURL;
@ -43,7 +44,12 @@ public class ComplexSerializerOptions {
public SelectOption getSelect() { public SelectOption getSelect() {
return select; return select;
} }
/** Serialize Edm.Int64 and Edm.Durration as strings **/
public boolean isIEEE754Compatible() {
return isIEEE754Compatible;
}
private ComplexSerializerOptions() {} private ComplexSerializerOptions() {}
/** Initializes the options builder. */ /** Initializes the options builder. */
@ -77,7 +83,13 @@ public class ComplexSerializerOptions {
options.select = select; options.select = select;
return this; return this;
} }
/** Set to serialize Edm.Int64 and Edm.Decimal as strings */
public Builder setIEEE754Compatible(final boolean isIEEE754Compatible) {
options.isIEEE754Compatible = isIEEE754Compatible;
return this;
}
/** Builds the OData serializer options. */ /** Builds the OData serializer options. */
public ComplexSerializerOptions build() { public ComplexSerializerOptions build() {
return options; return options;

View File

@ -31,7 +31,8 @@ public class EntityCollectionSerializerOptions {
private ExpandOption expand; private ExpandOption expand;
private SelectOption select; private SelectOption select;
private boolean onlyReferences; private boolean onlyReferences;
private boolean isIEEE754Compatible;
/** Gets the {@link ContextURL}. */ /** Gets the {@link ContextURL}. */
public ContextURL getContextURL() { public ContextURL getContextURL() {
return contextURL; return contextURL;
@ -57,6 +58,11 @@ public class EntityCollectionSerializerOptions {
return onlyReferences; return onlyReferences;
} }
/** Serialize Edm.Int64 and Edm.Durration as strings **/
public boolean isIEEE754Compatible() {
return isIEEE754Compatible;
}
/** Initializes the options builder. */ /** Initializes the options builder. */
public static Builder with() { public static Builder with() {
return new Builder(); return new Builder();
@ -100,7 +106,13 @@ public class EntityCollectionSerializerOptions {
options.onlyReferences = ref; options.onlyReferences = ref;
return this; return this;
} }
/** Set to serialize Edm.Int64 and Edm.Decimal as strings */
public Builder setIEEE754Compatible(final boolean isIEEE754Compatible) {
options.isIEEE754Compatible = isIEEE754Compatible;
return this;
}
/** Builds the OData serializer options. */ /** Builds the OData serializer options. */
public EntityCollectionSerializerOptions build() { public EntityCollectionSerializerOptions build() {
return options; return options;

View File

@ -28,7 +28,8 @@ public class EntitySerializerOptions {
private ExpandOption expand; private ExpandOption expand;
private SelectOption select; private SelectOption select;
private boolean onlyReferences; private boolean onlyReferences;
private boolean isIEEE754Compatible;
/** Gets the {@link ContextURL}. */ /** Gets the {@link ContextURL}. */
public ContextURL getContextURL() { public ContextURL getContextURL() {
return contextURL; return contextURL;
@ -49,6 +50,11 @@ public class EntitySerializerOptions {
return onlyReferences; return onlyReferences;
} }
/** Serialize Edm.Int64 and Edm.Durration as strings **/
public boolean isIEEE754Compatible() {
return isIEEE754Compatible;
}
private EntitySerializerOptions() {} private EntitySerializerOptions() {}
/** Initializes the options builder. */ /** Initializes the options builder. */
@ -88,7 +94,13 @@ public class EntitySerializerOptions {
options.onlyReferences = ref; options.onlyReferences = ref;
return this; return this;
} }
/** Set to serialize Edm.Int64 and Edm.Decimal as strings */
public Builder setIEEE754Compatible(final boolean isIEEE754Compatible) {
options.isIEEE754Compatible = isIEEE754Compatible;
return this;
}
/** Builds the OData serializer options. */ /** Builds the OData serializer options. */
public EntitySerializerOptions build() { public EntitySerializerOptions build() {
return options; return options;

View File

@ -18,7 +18,6 @@
*/ */
package org.apache.olingo.server.api.serializer; package org.apache.olingo.server.api.serializer;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection; import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.Property;
@ -119,18 +118,18 @@ public interface ODataSerializer {
* @param metadata metadata for the service * @param metadata metadata for the service
* @param edmEntitySet {@link EdmEntitySet} * @param edmEntitySet {@link EdmEntitySet}
* @param entity data of the entity * @param entity data of the entity
* @param contextURL {@link ContextURL} * @param options {@link ReferenceSerializerOptions}
*/ */
SerializerResult reference(ServiceMetadata metadata, EdmEntitySet edmEntitySet, Entity entity, SerializerResult reference(ServiceMetadata metadata, EdmEntitySet edmEntitySet, Entity entity,
ContextURL contextURL) throws SerializerException; ReferenceSerializerOptions options) throws SerializerException;
/** /**
* Writes entity-collection references into an InputStream. * Writes entity-collection references into an InputStream.
* @param metadata metadata for the service * @param metadata metadata for the service
* @param edmEntitySet {@link EdmEntitySet} * @param edmEntitySet {@link EdmEntitySet}
* @param entityCollection data of the entity collection * @param entityCollection data of the entity collection
* @param contextURL {@link ContextURL} * @param ReferenceCollectionSerializerOptions {@link ReferenceCollectionSerializerOptions}
*/ */
SerializerResult referenceCollection(ServiceMetadata metadata, EdmEntitySet edmEntitySet, SerializerResult referenceCollection(ServiceMetadata metadata, EdmEntitySet edmEntitySet,
EntityCollection entityCollection, ContextURL contextURL) throws SerializerException; EntityCollection entityCollection, ReferenceCollectionSerializerOptions options) throws SerializerException;
} }

View File

@ -30,7 +30,8 @@ public class PrimitiveSerializerOptions {
private Integer precision; private Integer precision;
private Integer scale; private Integer scale;
private Boolean isUnicode; private Boolean isUnicode;
private boolean isIEEE754Compatible;
/** Gets the {@link ContextURL}. */ /** Gets the {@link ContextURL}. */
public ContextURL getContextURL() { public ContextURL getContextURL() {
return contextURL; return contextURL;
@ -60,7 +61,12 @@ public class PrimitiveSerializerOptions {
public Boolean isUnicode() { public Boolean isUnicode() {
return isUnicode; return isUnicode;
} }
/** Serialize Edm.Int64 and Edm.Durration as strings **/
public boolean isIEEE754Compatible() {
return isIEEE754Compatible;
}
private PrimitiveSerializerOptions() {} private PrimitiveSerializerOptions() {}
/** Initializes the options builder. */ /** Initializes the options builder. */
@ -112,7 +118,13 @@ public class PrimitiveSerializerOptions {
options.isUnicode = isUnicode; options.isUnicode = isUnicode;
return this; return this;
} }
/** Set to serialize Edm.Int64 and Edm.Decimal as strings */
public Builder setIEEE754Compatible(final boolean isIEEE754Compatible) {
options.isIEEE754Compatible = isIEEE754Compatible;
return this;
}
/** Sets all facets from an EDM property. */ /** Sets all facets from an EDM property. */
public Builder facetsFrom(final EdmProperty property) { public Builder facetsFrom(final EdmProperty property) {
options.isNullable = property.isNullable(); options.isNullable = property.isNullable();

View File

@ -0,0 +1,83 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.api.serializer;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.server.api.uri.queryoption.CountOption;
/** Options for the OData serializer. */
public class ReferenceCollectionSerializerOptions {
private ContextURL contextURL;
private boolean isIEEE754Compatible;
private CountOption count;
/** Gets the {@link ContextURL}. */
public ContextURL getContextURL() {
return contextURL;
}
/** Gets the $count system query option. */
public CountOption getCount() {
return count;
}
/** Serialize Edm.Int64 and Edm.Durration as strings **/
public boolean isIEEE754Compatible() {
return isIEEE754Compatible;
}
private ReferenceCollectionSerializerOptions() {}
/** Initializes the options builder. */
public static Builder with() {
return new Builder();
}
/** Builder of OData serializer options. */
public static final class Builder {
private ReferenceCollectionSerializerOptions options;
public Builder() {
options = new ReferenceCollectionSerializerOptions();
}
/** Sets the {@link ContextURL}. */
public Builder contextURL(final ContextURL contextURL) {
options.contextURL = contextURL;
return this;
}
/** Sets the $count system query option. */
public Builder count(final CountOption count) {
options.count = count;
return this;
}
/** Set to serialize Edm.Int64 and Edm.Decimal as strings */
public Builder setIEEE754Compatible(final boolean isIEEE754Compatible) {
options.isIEEE754Compatible = isIEEE754Compatible;
return this;
}
/** Builds the OData serializer options. */
public ReferenceCollectionSerializerOptions build() {
return options;
}
}
}

View File

@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.api.serializer;
import org.apache.olingo.commons.api.data.ContextURL;
public class ReferenceSerializerOptions {
private ContextURL contextURL;
/** Gets the {@link ContextURL}. */
public ContextURL getContextURL() {
return contextURL;
}
private ReferenceSerializerOptions() {}
/** Initializes the options builder. */
public static Builder with() {
return new Builder();
}
/** Builder of OData serializer options. */
public static final class Builder {
private ReferenceSerializerOptions options;
public Builder() {
options = new ReferenceSerializerOptions();
}
/** Sets the {@link ContextURL}. */
public Builder contextURL(final ContextURL contextURL) {
options.contextURL = contextURL;
return this;
}
/** Builds the OData serializer options. */
public ReferenceSerializerOptions build() {
return options;
}
}
}

View File

@ -133,6 +133,18 @@ public class ContentNegotiator {
throw new IllegalArgumentException("charset not supported: " + acceptedType); throw new IllegalArgumentException("charset not supported: " + acceptedType);
} }
} }
if(acceptedType.getParameters().containsKey("ieee754compatible")) {
final String value = acceptedType.getParameters().get("ieee754compatible");
if("true".equalsIgnoreCase(value)) {
contentType = ContentType.create(contentType, ContentType.PARAMETER_IEEE754_COMPATIBLE);
} else if("false".equalsIgnoreCase(value)) {
contentType = ContentType.create(contentType, ContentType.PARAMETER_IEEE754_COMPATIBLE_FALSE);
} else {
throw new IllegalArgumentException("Invalid IEEE754Compatible value " + acceptedType);
}
}
if (acceptedType.matches(contentType)) { if (acceptedType.matches(contentType)) {
return contentType; return contentType;
} }

View File

@ -50,6 +50,8 @@ import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions
import org.apache.olingo.server.api.serializer.EntitySerializerOptions; import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions; import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
import org.apache.olingo.server.api.serializer.ReferenceCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.serializer.SerializerResult; import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.api.uri.UriHelper; import org.apache.olingo.server.api.uri.UriHelper;
@ -150,14 +152,14 @@ public class ODataJsonSerializer implements ODataSerializer {
if (options != null && options.getCount() != null && options.getCount().getValue() if (options != null && options.getCount() != null && options.getCount().getValue()
&& entitySet.getCount() != null) { && entitySet.getCount() != null) {
writeCount(entitySet, json); writeCount(entitySet, options == null ? false : options.isIEEE754Compatible(), 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, false, false, json);
} else { } else {
writeEntitySet(metadata, entityType, entitySet, writeEntitySet(metadata, entityType, entitySet,
options.getExpand(), options.getSelect(), options.onlyReferences(), json); options.getExpand(), options.getSelect(), options.onlyReferences(), options.isIEEE754Compatible(), json);
} }
if (entitySet.getNext() != null) { if (entitySet.getNext() != null) {
writeNextLink(entitySet, json); writeNextLink(entitySet, json);
@ -180,7 +182,8 @@ public class ODataJsonSerializer implements ODataSerializer {
writeEntity(metadata, entityType, entity, contextURL, writeEntity(metadata, entityType, entity, contextURL,
options == null ? null : options.getExpand(), options == null ? null : options.getExpand(),
options == null ? null : options.getSelect(), options == null ? null : options.getSelect(),
options == null ? false : options.onlyReferences(), json); options == null ? false : options.onlyReferences(),
options == null ? false : options.isIEEE754Compatible(), json);
json.close(); json.close();
} catch (final IOException e) { } catch (final IOException e) {
throw new SerializerException("An I/O exception occurred.", e, throw new SerializerException("An I/O exception occurred.", e,
@ -210,7 +213,7 @@ public class ODataJsonSerializer implements ODataSerializer {
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType, protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
final EntityCollection entitySet, final ExpandOption expand, final SelectOption select, final EntityCollection entitySet, final ExpandOption expand, final SelectOption select,
final boolean onlyReference, final JsonGenerator json) throws IOException, final boolean onlyReference, final boolean isIEEE754Compatible, final JsonGenerator json) throws IOException,
SerializerException { SerializerException {
json.writeStartArray(); json.writeStartArray();
for (final Entity entity : entitySet.getEntities()) { for (final Entity entity : entitySet.getEntities()) {
@ -219,7 +222,7 @@ public class ODataJsonSerializer implements ODataSerializer {
json.writeStringField(Constants.JSON_ID, entity.getId().toASCIIString()); json.writeStringField(Constants.JSON_ID, entity.getId().toASCIIString());
json.writeEndObject(); json.writeEndObject();
} else { } else {
writeEntity(metadata, entityType, entity, null, expand, select, false, json); writeEntity(metadata, entityType, entity, null, expand, select, false, isIEEE754Compatible, json);
} }
} }
json.writeEndArray(); json.writeEndArray();
@ -227,8 +230,8 @@ public class ODataJsonSerializer implements ODataSerializer {
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 SelectOption select, final boolean onlyReference, final JsonGenerator json) final SelectOption select, final boolean onlyReference, final boolean isIEEE7854Compatible,
throws IOException, SerializerException { final JsonGenerator json) throws IOException, SerializerException {
json.writeStartObject(); json.writeStartObject();
if (format != ODataFormat.JSON_NO_METADATA) { if (format != ODataFormat.JSON_NO_METADATA) {
if (contextURL != null) { // top-level entity if (contextURL != null) { // top-level entity
@ -260,8 +263,8 @@ public class ODataJsonSerializer implements ODataSerializer {
if (!resolvedType.equals(entityType)) { if (!resolvedType.equals(entityType)) {
json.writeStringField(Constants.JSON_TYPE, "#" + entity.getType()); json.writeStringField(Constants.JSON_TYPE, "#" + entity.getType());
} }
writeProperties(resolvedType, entity.getProperties(), select, json); writeProperties(resolvedType, entity.getProperties(), select, isIEEE7854Compatible, json);
writeNavigationProperties(metadata, resolvedType, entity, expand, json); writeNavigationProperties(metadata, resolvedType, entity, expand, isIEEE7854Compatible, json);
json.writeEndObject(); json.writeEndObject();
} }
} }
@ -315,7 +318,8 @@ public class ODataJsonSerializer implements ODataSerializer {
} }
protected void writeProperties(final EdmStructuredType type, final List<Property> properties, protected void writeProperties(final EdmStructuredType type, final List<Property> properties,
final SelectOption select, final JsonGenerator json) throws IOException, SerializerException { final SelectOption select, final boolean isIEEE754Compatible, final JsonGenerator json)
throws IOException, SerializerException {
final boolean all = ExpandSelectHelper.isAll(select); final boolean all = ExpandSelectHelper.isAll(select);
final Set<String> selected = all ? null : final Set<String> selected = all ? null :
ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems()); ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems());
@ -325,14 +329,14 @@ public class ODataJsonSerializer implements ODataSerializer {
final Property property = findProperty(propertyName, properties); final Property property = findProperty(propertyName, properties);
final Set<List<String>> selectedPaths = all || edmProperty.isPrimitive() ? null : final Set<List<String>> selectedPaths = all || edmProperty.isPrimitive() ? null :
ExpandSelectHelper.getSelectedPaths(select.getSelectItems(), propertyName); ExpandSelectHelper.getSelectedPaths(select.getSelectItems(), propertyName);
writeProperty(edmProperty, property, selectedPaths, json); writeProperty(edmProperty, property, selectedPaths, isIEEE754Compatible, json);
} }
} }
} }
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 JsonGenerator json) throws SerializerException, IOException { final boolean isIEEE754Compatible, final JsonGenerator json) throws SerializerException, IOException {
if (ExpandSelectHelper.hasExpand(expand)) { if (ExpandSelectHelper.hasExpand(expand)) {
final boolean expandAll = ExpandSelectHelper.isExpandAll(expand); final boolean expandAll = ExpandSelectHelper.isExpandAll(expand);
final Set<String> expanded = expandAll ? null : final Set<String> expanded = expandAll ? null :
@ -349,9 +353,8 @@ public class ODataJsonSerializer implements ODataSerializer {
} }
writeExpandedNavigationProperty(metadata, property, navigationLink, writeExpandedNavigationProperty(metadata, property, navigationLink,
innerOptions == null ? null : innerOptions.getExpandOption(), innerOptions == null ? null : innerOptions.getExpandOption(),
innerOptions == null ? null : innerOptions.getSelectOption(), innerOptions == null ? null : innerOptions.getSelectOption(),
innerOptions == null ? false: innerOptions.isRef(), isIEEE754Compatible, json);
json);
} }
} }
} }
@ -359,7 +362,7 @@ public class ODataJsonSerializer implements ODataSerializer {
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, boolean onlyReference, final ExpandOption innerExpand, final SelectOption innerSelect, final boolean isIEEE754Compatible,
final JsonGenerator json) final JsonGenerator json)
throws IOException, SerializerException { throws IOException, SerializerException {
json.writeFieldName(property.getName()); json.writeFieldName(property.getName());
@ -369,20 +372,21 @@ public class ODataJsonSerializer implements ODataSerializer {
json.writeEndArray(); json.writeEndArray();
} else { } else {
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand, writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
innerSelect, onlyReference, json); innerSelect, false, isIEEE754Compatible, json);
} }
} else { } else {
if (navigationLink == null || navigationLink.getInlineEntity() == null) { if (navigationLink == null || navigationLink.getInlineEntity() == null) {
json.writeNull(); json.writeNull();
} else { } else {
writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null, writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null,
innerExpand, innerSelect, onlyReference, json); innerExpand, innerSelect, false, isIEEE754Compatible, json);
} }
} }
} }
protected void writeProperty(final EdmProperty edmProperty, final Property property, protected void writeProperty(final EdmProperty edmProperty, final Property property,
final Set<List<String>> selectedPaths, final JsonGenerator json) throws IOException, SerializerException { final Set<List<String>> selectedPaths, final boolean isIEEE754Compatible, final JsonGenerator json)
throws IOException, SerializerException {
json.writeFieldName(edmProperty.getName()); json.writeFieldName(edmProperty.getName());
if (property == null || property.isNull()) { if (property == null || property.isNull()) {
if (edmProperty.isNullable() == Boolean.FALSE) { if (edmProperty.isNullable() == Boolean.FALSE) {
@ -392,36 +396,38 @@ public class ODataJsonSerializer implements ODataSerializer {
json.writeNull(); json.writeNull();
} }
} else { } else {
writePropertyValue(edmProperty, property, selectedPaths, json); writePropertyValue(edmProperty, property, selectedPaths, isIEEE754Compatible, json);
} }
} }
private void writePropertyValue(final EdmProperty edmProperty, private void writePropertyValue(final EdmProperty edmProperty,
final Property property, final Set<List<String>> selectedPaths, final Property property, final Set<List<String>> selectedPaths,
final JsonGenerator json) throws IOException, SerializerException { final boolean isIEEE754Compatible, final JsonGenerator json) throws IOException, SerializerException {
try { try {
if (edmProperty.isPrimitive()) { if (edmProperty.isPrimitive()) {
if (edmProperty.isCollection()) { if (edmProperty.isCollection()) {
writePrimitiveCollection((EdmPrimitiveType) edmProperty.getType(), property, writePrimitiveCollection((EdmPrimitiveType) edmProperty.getType(), property,
edmProperty.isNullable(), edmProperty.getMaxLength(), edmProperty.isNullable(), edmProperty.getMaxLength(),
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
isIEEE754Compatible,
json); json);
} else { } else {
writePrimitive((EdmPrimitiveType) edmProperty.getType(), property, writePrimitive((EdmPrimitiveType) edmProperty.getType(), property,
edmProperty.isNullable(), edmProperty.getMaxLength(), edmProperty.isNullable(), edmProperty.getMaxLength(),
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
json); isIEEE754Compatible, json);
} }
} else if (edmProperty.isCollection()) { } else if (edmProperty.isCollection()) {
writeComplexCollection((EdmComplexType) edmProperty.getType(), property, selectedPaths, json); writeComplexCollection((EdmComplexType) edmProperty.getType(), property,
selectedPaths, isIEEE754Compatible, json);
} else if (property.isComplex()) { } else if (property.isComplex()) {
writeComplexValue((EdmComplexType) edmProperty.getType(), property.asComplex().getValue(), writeComplexValue((EdmComplexType) edmProperty.getType(), property.asComplex().getValue(),
selectedPaths, json); selectedPaths, isIEEE754Compatible, json);
} else if (property.isEnum()) { } else if (property.isEnum()) {
writePrimitive((EdmPrimitiveType) edmProperty.getType(), property, writePrimitive((EdmPrimitiveType) edmProperty.getType(), property,
edmProperty.isNullable(), edmProperty.getMaxLength(), edmProperty.isNullable(), edmProperty.getMaxLength(),
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
json); isIEEE754Compatible, json);
} else { } else {
throw new SerializerException("Property type not yet supported!", throw new SerializerException("Property type not yet supported!",
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, edmProperty.getName()); SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, edmProperty.getName());
@ -436,12 +442,13 @@ public class ODataJsonSerializer implements ODataSerializer {
private void writePrimitiveCollection(final EdmPrimitiveType type, final Property property, private void writePrimitiveCollection(final EdmPrimitiveType type, final Property property,
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale, final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
final Boolean isUnicode, final Boolean isUnicode,
final JsonGenerator json) throws IOException, EdmPrimitiveTypeException, SerializerException { final boolean isIEEE754Compatible, final JsonGenerator json)
throws IOException, EdmPrimitiveTypeException, SerializerException {
json.writeStartArray(); json.writeStartArray();
for (Object value : property.asCollection()) { for (Object value : property.asCollection()) {
switch (property.getValueType()) { switch (property.getValueType()) {
case COLLECTION_PRIMITIVE: case COLLECTION_PRIMITIVE:
writePrimitiveValue(type, value, isNullable, maxLength, precision, scale, isUnicode, json); writePrimitiveValue(type, value, isNullable, maxLength, precision, scale, isUnicode, isIEEE754Compatible, json);
break; break;
case COLLECTION_GEOSPATIAL: case COLLECTION_GEOSPATIAL:
throw new SerializerException("Property type not yet supported!", throw new SerializerException("Property type not yet supported!",
@ -458,13 +465,13 @@ public class ODataJsonSerializer implements ODataSerializer {
} }
private void writeComplexCollection(final EdmComplexType type, final Property property, private void writeComplexCollection(final EdmComplexType type, final Property property,
final Set<List<String>> selectedPaths, final JsonGenerator json) final Set<List<String>> selectedPaths, final boolean isIEEE754Compatible, final JsonGenerator json)
throws IOException, EdmPrimitiveTypeException, SerializerException { throws IOException, EdmPrimitiveTypeException, SerializerException {
json.writeStartArray(); json.writeStartArray();
for (Object value : property.asCollection()) { for (Object value : property.asCollection()) {
switch (property.getValueType()) { switch (property.getValueType()) {
case COLLECTION_COMPLEX: case COLLECTION_COMPLEX:
writeComplexValue(type, ((ComplexValue) value).getValue(), selectedPaths, json); writeComplexValue(type, ((ComplexValue) value).getValue(), selectedPaths, isIEEE754Compatible, json);
break; break;
default: default:
throw new SerializerException("Property type not yet supported!", throw new SerializerException("Property type not yet supported!",
@ -476,17 +483,17 @@ public class ODataJsonSerializer implements ODataSerializer {
private void writePrimitive(final EdmPrimitiveType type, final Property property, private void writePrimitive(final EdmPrimitiveType type, final Property property,
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale, final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
final Boolean isUnicode, final JsonGenerator json) final Boolean isUnicode, final boolean isIEEE754Compatible, final JsonGenerator json)
throws EdmPrimitiveTypeException, IOException, SerializerException { throws EdmPrimitiveTypeException, IOException, SerializerException {
if (property.isPrimitive()) { if (property.isPrimitive()) {
writePrimitiveValue(type, property.asPrimitive(), writePrimitiveValue(type, property.asPrimitive(),
isNullable, maxLength, precision, scale, isUnicode, json); isNullable, maxLength, precision, scale, isUnicode, isIEEE754Compatible, json);
} else if (property.isGeospatial()) { } else if (property.isGeospatial()) {
throw new SerializerException("Property type not yet supported!", throw new SerializerException("Property type not yet supported!",
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName()); SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
} else if (property.isEnum()) { } else if (property.isEnum()) {
writePrimitiveValue(type, property.asEnum(), writePrimitiveValue(type, property.asEnum(),
isNullable, maxLength, precision, scale, isUnicode, json); isNullable, maxLength, precision, scale, isUnicode, isIEEE754Compatible, json);
} else { } else {
throw new SerializerException("Inconsistent property type!", throw new SerializerException("Inconsistent property type!",
SerializerException.MessageKeys.INCONSISTENT_PROPERTY_TYPE, property.getName()); SerializerException.MessageKeys.INCONSISTENT_PROPERTY_TYPE, property.getName());
@ -496,13 +503,17 @@ public class ODataJsonSerializer implements ODataSerializer {
protected void writePrimitiveValue(final EdmPrimitiveType type, final Object primitiveValue, protected void writePrimitiveValue(final EdmPrimitiveType type, final Object primitiveValue,
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale, final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
final Boolean isUnicode, final Boolean isUnicode,
final JsonGenerator json) throws EdmPrimitiveTypeException, IOException { final boolean isIEEE754Compatible, final JsonGenerator json) throws EdmPrimitiveTypeException, IOException {
final String value = type.valueToString(primitiveValue, final String value = type.valueToString(primitiveValue,
isNullable, maxLength, precision, scale, isUnicode); isNullable, maxLength, precision, scale, isUnicode);
if (value == null) { if (value == null) {
json.writeNull(); json.writeNull();
} else if(type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean)) { } else if(type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean)) {
json.writeBoolean(Boolean.parseBoolean(value)); json.writeBoolean(Boolean.parseBoolean(value));
} else if(isIEEE754Compatible &&
( type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64)
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal))) {
json.writeString(value.toString());
} else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Byte) } else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Byte)
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal) || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Double) || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Double)
@ -518,7 +529,7 @@ public class ODataJsonSerializer implements ODataSerializer {
} }
protected void writeComplexValue(final EdmComplexType type, final List<Property> properties, protected void writeComplexValue(final EdmComplexType type, final List<Property> properties,
final Set<List<String>> selectedPaths, final JsonGenerator json) final Set<List<String>> selectedPaths, final boolean isIEEE754Compatible, final JsonGenerator json)
throws IOException, EdmPrimitiveTypeException, SerializerException { throws IOException, EdmPrimitiveTypeException, SerializerException {
json.writeStartObject(); json.writeStartObject();
for (final String propertyName : type.getPropertyNames()) { for (final String propertyName : type.getPropertyNames()) {
@ -526,7 +537,7 @@ public class ODataJsonSerializer implements ODataSerializer {
if (selectedPaths == null || ExpandSelectHelper.isSelected(selectedPaths, propertyName)) { if (selectedPaths == null || ExpandSelectHelper.isSelected(selectedPaths, propertyName)) {
writeProperty((EdmProperty) type.getProperty(propertyName), property, writeProperty((EdmProperty) type.getProperty(propertyName), property,
selectedPaths == null ? null : ExpandSelectHelper.getReducedSelectedPaths(selectedPaths, propertyName), selectedPaths == null ? null : ExpandSelectHelper.getReducedSelectedPaths(selectedPaths, propertyName),
json); isIEEE754Compatible, json);
} }
} }
json.writeEndObject(); json.writeEndObject();
@ -559,8 +570,7 @@ public class ODataJsonSerializer implements ODataSerializer {
json.writeFieldName(Constants.VALUE); json.writeFieldName(Constants.VALUE);
writePrimitive(type, property, writePrimitive(type, property,
options.isNullable(), options.getMaxLength(), options.getPrecision(), options.getScale(), options.isNullable(), options.getMaxLength(), options.getPrecision(), options.getScale(),
options.isUnicode(), options.isUnicode(), options.isIEEE754Compatible(), json);
json);
} }
json.writeEndObject(); json.writeEndObject();
json.close(); json.close();
@ -593,10 +603,10 @@ public class ODataJsonSerializer implements ODataSerializer {
} }
final List<Property> values = final List<Property> values =
property.isNull() ? Collections.<Property> emptyList() : property.asComplex().getValue(); property.isNull() ? Collections.<Property> emptyList() : property.asComplex().getValue();
writeProperties(type, values, options == null ? null : options.getSelect(), json); writeProperties(type, values, options == null ? null : options.getSelect(), options.isIEEE754Compatible(), 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(), options.isIEEE754Compatible(), json);
} }
json.writeEndObject(); json.writeEndObject();
json.close(); json.close();
@ -622,8 +632,7 @@ public class ODataJsonSerializer implements ODataSerializer {
json.writeFieldName(Constants.VALUE); json.writeFieldName(Constants.VALUE);
writePrimitiveCollection(type, property, writePrimitiveCollection(type, property,
options.isNullable(), options.getMaxLength(), options.getPrecision(), options.getScale(), options.isNullable(), options.getMaxLength(), options.getPrecision(), options.getScale(),
options.isUnicode(), options.isUnicode(), options.isIEEE754Compatible(), json);
json);
json.writeEndObject(); json.writeEndObject();
json.close(); json.close();
} catch (final IOException e) { } catch (final IOException e) {
@ -650,7 +659,7 @@ public class ODataJsonSerializer implements ODataSerializer {
} }
writeMetadataETag(metadata, json); writeMetadataETag(metadata, json);
json.writeFieldName(Constants.VALUE); json.writeFieldName(Constants.VALUE);
writeComplexCollection(type, property, null, json); writeComplexCollection(type, property, null, options.isIEEE754Compatible(), json);
json.writeEndObject(); json.writeEndObject();
json.close(); json.close();
} catch (final IOException e) { } catch (final IOException e) {
@ -666,8 +675,8 @@ public class ODataJsonSerializer implements ODataSerializer {
@Override @Override
public SerializerResult reference(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, public SerializerResult reference(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
final Entity entity, final ContextURL contextURL) throws SerializerException { final Entity entity, final ReferenceSerializerOptions options) throws SerializerException {
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
final CircleStreamBuffer buffer = new CircleStreamBuffer(); final CircleStreamBuffer buffer = new CircleStreamBuffer();
final UriHelper uriHelper = new UriHelperImpl(); final UriHelper uriHelper = new UriHelperImpl();
@ -685,8 +694,9 @@ public class ODataJsonSerializer implements ODataSerializer {
@Override @Override
public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
final EntityCollection entityCollection, final ContextURL contextURL) throws SerializerException { final EntityCollection entityCollection, final ReferenceCollectionSerializerOptions options)
throws SerializerException {
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
final CircleStreamBuffer buffer = new CircleStreamBuffer(); final CircleStreamBuffer buffer = new CircleStreamBuffer();
final UriHelper uriHelper = new UriHelperImpl(); final UriHelper uriHelper = new UriHelperImpl();
@ -694,12 +704,12 @@ public class ODataJsonSerializer implements ODataSerializer {
final JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); final JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
json.writeStartObject(); json.writeStartObject();
if(entityCollection.getCount() != null) {
writeCount(entityCollection, json);
}
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString()); json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
writeMetadataETag(metadata, json); writeMetadataETag(metadata, json);
if(options != null && options.getCount() != null) {
writeCount(entityCollection, (options == null) ? false : options.isIEEE754Compatible(), json);
}
writeReferenceCollection(edmEntitySet, entityCollection, uriHelper,json); writeReferenceCollection(edmEntitySet, entityCollection, uriHelper,json);
if(entityCollection.getNext() != null) { if(entityCollection.getNext() != null) {
@ -718,7 +728,7 @@ public class ODataJsonSerializer implements ODataSerializer {
protected void writeReferenceCollection(final EdmEntitySet edmEntitySet, final EntityCollection entityCollection, protected void writeReferenceCollection(final EdmEntitySet edmEntitySet, final EntityCollection entityCollection,
final UriHelper uriHelper, final JsonGenerator json) throws IOException, SerializerException { final UriHelper uriHelper, final JsonGenerator json) throws IOException, SerializerException {
json.writeArrayFieldStart(Constants.VALUE); json.writeArrayFieldStart(Constants.VALUE);
for(final Entity entity : entityCollection.getEntities()) { for(final Entity entity : entityCollection.getEntities()) {
writeReference(null, edmEntitySet, entity, null, uriHelper, json); writeReference(null, edmEntitySet, entity, null, uriHelper, json);
} }
@ -739,8 +749,13 @@ public class ODataJsonSerializer implements ODataSerializer {
json.writeEndObject(); json.writeEndObject();
} }
private void writeCount(final EntityCollection entitySet, JsonGenerator json) throws IOException { private void writeCount(final EntityCollection entitySet, final boolean isIEEE754Comptible, final JsonGenerator json)
json.writeNumberField(Constants.JSON_COUNT, entitySet.getCount()); throws IOException {
if(isIEEE754Comptible) {
json.writeStringField(Constants.JSON_COUNT, entitySet.getCount().toString());
} else {
json.writeNumberField(Constants.JSON_COUNT, entitySet.getCount());
}
} }
private void writeNextLink(final EntityCollection entitySet, JsonGenerator json) throws IOException { private void writeNextLink(final EntityCollection entitySet, JsonGenerator json) throws IOException {

View File

@ -22,7 +22,6 @@ import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter; import javax.xml.stream.XMLStreamWriter;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection; import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.Property;
@ -37,6 +36,8 @@ import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions
import org.apache.olingo.server.api.serializer.EntitySerializerOptions; import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions; import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
import org.apache.olingo.server.api.serializer.ReferenceCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.serializer.SerializerResult; import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.core.serializer.SerializerResultImpl; import org.apache.olingo.server.core.serializer.SerializerResultImpl;
@ -139,14 +140,15 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
@Override @Override
public SerializerResult reference(final ServiceMetadata metadata, final EdmEntitySet edmEntotySet, public SerializerResult reference(final ServiceMetadata metadata, final EdmEntitySet edmEntotySet,
final Entity entity, final ContextURL contextURL) throws SerializerException { final Entity entity, final ReferenceSerializerOptions options) throws SerializerException {
throw new SerializerException("Serialization not implemented for XML format.", throw new SerializerException("Serialization not implemented for XML format.",
SerializerException.MessageKeys.NOT_IMPLEMENTED); SerializerException.MessageKeys.NOT_IMPLEMENTED);
} }
@Override @Override
public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
final EntityCollection entityCollection, final ContextURL contextURL) throws SerializerException { final EntityCollection entityCollection, final ReferenceCollectionSerializerOptions optionsL)
throws SerializerException {
throw new SerializerException("Serialization not implemented for XML format.", throw new SerializerException("Serialization not implemented for XML format.",
SerializerException.MessageKeys.NOT_IMPLEMENTED); SerializerException.MessageKeys.NOT_IMPLEMENTED);
} }

View File

@ -46,32 +46,39 @@ public class ContentNegotiatorTest {
static final private String ACCEPT_CASE_MIN_UTF8 = "application/json;charset=UTF-8;odata.metadata=minimal"; static final private String ACCEPT_CASE_MIN_UTF8 = "application/json;charset=UTF-8;odata.metadata=minimal";
static final private String ACCEPT_CASE_FULL = "application/json;odata.metadata=full"; static final private String ACCEPT_CASE_FULL = "application/json;odata.metadata=full";
static final private String ACCEPT_CASE_NONE = "application/json;odata.metadata=none"; static final private String ACCEPT_CASE_NONE = "application/json;odata.metadata=none";
static final private String ACCEPT_CASE_MIN_UTF8_IEEE754
= "application/json;charset=UTF-8;odata.metadata=minimal;IEEE754Compatible=true";
static final private String ACCEPT_CASE_MIN_IEEE754
= "application/json;odata.metadata=minimal;IEEE754Compatible=true";
static final private String ACCEPT_CASE_JSONQ = "application/json;q=0.2"; static final private String ACCEPT_CASE_JSONQ = "application/json;q=0.2";
static final private String ACCEPT_CASE_XML = HttpContentType.APPLICATION_XML; static final private String ACCEPT_CASE_XML = HttpContentType.APPLICATION_XML;
static final private String ACCEPT_CASE_WILDCARD1 = HttpContentType.WILDCARD; static final private String ACCEPT_CASE_WILDCARD1 = HttpContentType.WILDCARD;
static final private String ACCEPT_CASE_WILDCARD2 = "application/*"; static final private String ACCEPT_CASE_WILDCARD2 = "application/*";
//@formatter:off (Eclipse formatter) //@formatter:off (Eclipse formatter)
//CHECKSTYLE:OFF (Maven checkstyle) //CHECKSTYLE:OFF (Maven checkstyle)
String[][] casesServiceDocument = { String[][] casesServiceDocument = {
/* expected $format accept modified content types */ /* expected $format accept modified content types */
{ ACCEPT_CASE_MIN, null, null, null }, { ACCEPT_CASE_MIN, null, null, null },
{ ACCEPT_CASE_MIN, "json", null, null }, { ACCEPT_CASE_MIN, "json", null, null },
{ ACCEPT_CASE_MIN, "json", ACCEPT_CASE_JSONQ, null }, { ACCEPT_CASE_MIN, "json", ACCEPT_CASE_JSONQ, null },
{ ACCEPT_CASE_NONE, ACCEPT_CASE_NONE, null, null }, { ACCEPT_CASE_NONE, ACCEPT_CASE_NONE, null, null },
{ "a/a", "a/a", null, "a/a" }, { "a/a", "a/a", null, "a/a" },
{ ACCEPT_CASE_MIN, null, ACCEPT_CASE_JSONQ, null }, { ACCEPT_CASE_MIN, null, ACCEPT_CASE_JSONQ, null },
{ ACCEPT_CASE_MIN, null, ACCEPT_CASE_WILDCARD1, null }, { ACCEPT_CASE_MIN, null, ACCEPT_CASE_WILDCARD1, null },
{ ACCEPT_CASE_MIN, null, ACCEPT_CASE_WILDCARD2, null }, { ACCEPT_CASE_MIN, null, ACCEPT_CASE_WILDCARD2, null },
{ ACCEPT_CASE_MIN, null, null, ACCEPT_CASE_MIN }, { ACCEPT_CASE_MIN, null, null, ACCEPT_CASE_MIN },
{ "a/a", "a/a", null, "a/a,b/b" }, { "a/a", "a/a", null, "a/a,b/b" },
{ "a/a;x=y", "a/a", ACCEPT_CASE_WILDCARD1, "a/a;x=y" }, { "a/a;x=y", "a/a", ACCEPT_CASE_WILDCARD1, "a/a;x=y" },
{ "a/a;v=w;x=y", null, "a/a;x=y", "a/a;b=c,a/a;v=w;x=y" }, { "a/a;v=w;x=y", null, "a/a;x=y", "a/a;b=c,a/a;v=w;x=y" },
{ "a/a;v=w;x=y", "a/a;x=y", null, "a/a;b=c,a/a;v=w;x=y" }, { "a/a;v=w;x=y", "a/a;x=y", null, "a/a;b=c,a/a;v=w;x=y" },
{ ACCEPT_CASE_MIN, "json", ACCEPT_CASE_MIN, null }, { ACCEPT_CASE_MIN, "json", ACCEPT_CASE_MIN, null },
{ ACCEPT_CASE_FULL, null, ACCEPT_CASE_FULL, ACCEPT_CASE_FULL }, { ACCEPT_CASE_FULL, null, ACCEPT_CASE_FULL, ACCEPT_CASE_FULL },
{ ACCEPT_CASE_MIN_UTF8, null, ACCEPT_CASE_MIN_UTF8, null } { ACCEPT_CASE_MIN_UTF8, null, ACCEPT_CASE_MIN_UTF8, null },
{ ACCEPT_CASE_MIN_IEEE754, null, ACCEPT_CASE_MIN_IEEE754, null },
{ ACCEPT_CASE_MIN_UTF8_IEEE754, null, ACCEPT_CASE_MIN_UTF8_IEEE754, null },
{ ACCEPT_CASE_MIN_IEEE754, ACCEPT_CASE_MIN_IEEE754, ACCEPT_CASE_MIN , null },
}; };
String[][] casesMetadata = { String[][] casesMetadata = {

View File

@ -48,6 +48,8 @@ import org.apache.olingo.server.api.processor.ReferenceCollectionProcessor;
import org.apache.olingo.server.api.processor.ReferenceProcessor; import org.apache.olingo.server.api.processor.ReferenceProcessor;
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions; import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.EntitySerializerOptions; import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
import org.apache.olingo.server.api.serializer.ReferenceCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
import org.apache.olingo.server.api.serializer.SerializerResult; import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResourceEntitySet; import org.apache.olingo.server.api.uri.UriResourceEntitySet;
@ -435,8 +437,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
final CountOption countOption = uriInfo.getCountOption(); final CountOption countOption = uriInfo.getCountOption();
// Serialize // Serialize
final SerializerResult serializerResult = isReference ? final SerializerResult serializerResult = (isReference) ?
serializeReferenceCollection(entitySetSerialization, edmEntitySet, format) : serializeReferenceCollection(entitySetSerialization, edmEntitySet, format, countOption) :
serializeEntityCollection(entitySetSerialization, edmEntitySet, edmEntityType, format, serializeEntityCollection(entitySetSerialization, edmEntitySet, edmEntityType, format,
expand, select, countOption); expand, select, countOption);
@ -461,18 +463,23 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
.build()); .build());
} }
private SerializerResult serializeReferenceCollection(final EntityCollection entityCollection, private SerializerResult serializeReferenceCollection(final EntityCollection entityCollection,
final EdmEntitySet edmEntitySet, final ODataFormat format) throws ODataLibraryException { final EdmEntitySet edmEntitySet, final ODataFormat format, final CountOption countOption)
throws ODataLibraryException {
return odata.createSerializer(format) return odata.createSerializer(format)
.referenceCollection(serviceMetadata, edmEntitySet, entityCollection, .referenceCollection(serviceMetadata, edmEntitySet, entityCollection,ReferenceCollectionSerializerOptions.with()
ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build()); .contextURL(ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build())
.count(countOption)
.setIEEE754Compatible(false).build());
} }
private SerializerResult serializeReference(final Entity entity, final EdmEntitySet edmEntitySet, private SerializerResult serializeReference(final Entity entity, final EdmEntitySet edmEntitySet,
final ODataFormat format) throws ODataLibraryException { final ODataFormat format) throws ODataLibraryException {
return odata.createSerializer(format) return odata.createSerializer(format)
.reference(serviceMetadata, edmEntitySet, entity, .reference(serviceMetadata, edmEntitySet, entity, ReferenceSerializerOptions.with()
ContextURL.with().suffix(Suffix.REFERENCE).build()); .contextURL(ContextURL.with().suffix(Suffix.REFERENCE).build()).build());
} }
private SerializerResult serializeEntity(final Entity entity, private SerializerResult serializeEntity(final Entity entity,

View File

@ -50,9 +50,11 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset; import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.deserializer.DeserializerException; import org.apache.olingo.server.api.deserializer.DeserializerException;
import org.apache.olingo.server.api.deserializer.DeserializerResult;
import org.apache.olingo.server.api.deserializer.ODataDeserializer; import org.apache.olingo.server.api.deserializer.ODataDeserializer;
import org.apache.olingo.server.api.edmx.EdmxReference; import org.apache.olingo.server.api.edmx.EdmxReference;
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTest { public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTest {
@ -1412,7 +1414,37 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe
throw e; throw e;
} }
} }
@Test
@Ignore
public void ieee754Compatible() throws Exception {
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
String entityString =
"{\"PropertyInt16\":32767," +
"\"PropertyString\":\"First Resource - positive values\"," +
"\"PropertyBoolean\":null," +
"\"PropertyByte\":255," +
"\"PropertySByte\":127," +
"\"PropertyInt32\":2147483647," +
"\"PropertyInt64\":\"9223372036854775807\"," +
"\"PropertySingle\":1.79E20," +
"\"PropertyDouble\":-1.79E19," +
"\"PropertyDecimal\":\"34\"," +
"\"PropertyBinary\":\"ASNFZ4mrze8=\"," +
"\"PropertyDate\":null," +
"\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\"," +
"\"PropertyDuration\":\"PT6S\"," +
"\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," +
"\"PropertyTimeOfDay\":\"03:26:05\"}";
final InputStream stream = new ByteArrayInputStream(entityString.getBytes());
final Entity entity = deserializer
.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity();
assertEquals(9223372036854775807L, entity.getProperty("PropertyInt64").asPrimitive());
assertEquals(34, entity.getProperty("PropertyDecimal").asPrimitive());
}
private void checkPropertyJsonType(final String entityString) throws DeserializerException { private void checkPropertyJsonType(final String entityString) throws DeserializerException {
InputStream stream = new ByteArrayInputStream(entityString.getBytes()); InputStream stream = new ByteArrayInputStream(entityString.getBytes());
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON); ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);

View File

@ -44,6 +44,8 @@ import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions
import org.apache.olingo.server.api.serializer.EntitySerializerOptions; import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions; import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
import org.apache.olingo.server.api.serializer.ReferenceCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.serializer.SerializerResult; import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.api.uri.UriHelper; import org.apache.olingo.server.api.uri.UriHelper;
@ -711,7 +713,7 @@ public class ODataJsonSerializerTest {
+ "\"PropertyInt16\":111,\"PropertyString\":\"TEST A\"}", + "\"PropertyInt16\":111,\"PropertyString\":\"TEST A\"}",
resultString); resultString);
} }
@Test @Test
public void complexCollectionProperty() throws Exception { public void complexCollectionProperty() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp"); final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp");
@ -740,7 +742,7 @@ public class ODataJsonSerializerTest {
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0); final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
final SerializerResult serializerResult = serializer.reference(metadata, edmEntitySet, entity, final SerializerResult serializerResult = serializer.reference(metadata, edmEntitySet, entity,
ContextURL.with().suffix(Suffix.REFERENCE).build()); ReferenceSerializerOptions.with().contextURL(ContextURL.with().suffix(Suffix.REFERENCE).build()).build());
final String resultString = IOUtils.toString(serializerResult.getContent()); final String resultString = IOUtils.toString(serializerResult.getContent());
Assert.assertEquals("{\"@odata.context\":\"$metadata#$ref\"," Assert.assertEquals("{\"@odata.context\":\"$metadata#$ref\","
@ -754,11 +756,13 @@ public class ODataJsonSerializerTest {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim"); final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
final EntityCollection entityCollection = data.readAll(edmEntitySet); final EntityCollection entityCollection = data.readAll(edmEntitySet);
final SerializerResult serializerResult = serializer.referenceCollection(metadata, final SerializerResult serializerResult = serializer.referenceCollection(metadata,
edmEntitySet, edmEntitySet,
entityCollection, entityCollection,
ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build()); ReferenceCollectionSerializerOptions.with()
.contextURL(ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build())
.setIEEE754Compatible(false).build());
final String resultString = IOUtils.toString(serializerResult.getContent()); final String resultString = IOUtils.toString(serializerResult.getContent());
Assert.assertEquals("{\"@odata.context\":\"$metadata#Collection($ref)\"," Assert.assertEquals("{\"@odata.context\":\"$metadata#Collection($ref)\","
@ -774,15 +778,219 @@ public class ODataJsonSerializerTest {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim"); final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
final EntityCollection entityCollection = new EntityCollection(); final EntityCollection entityCollection = new EntityCollection();
final SerializerResult serializerResult = serializer.referenceCollection(metadata, final SerializerResult serializerResult = serializer.referenceCollection(metadata,
edmEntitySet, edmEntitySet, entityCollection,
entityCollection, ReferenceCollectionSerializerOptions.with()
ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build()); .contextURL(ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build())
.setIEEE754Compatible(false).build());
final String resultString = IOUtils.toString(serializerResult.getContent()); final String resultString = IOUtils.toString(serializerResult.getContent());
Assert.assertEquals("{\"@odata.context\":\"$metadata#Collection($ref)\"," Assert.assertEquals("{\"@odata.context\":\"$metadata#Collection($ref)\","
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+ "\"value\":[]}", resultString); + "\"value\":[]}", resultString);
} }
@Test
public void entityIEE754Compatible() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
EntitySerializerOptions.with()
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
.setIEEE754Compatible(true)
.build()).getContent();
final String resultString = IOUtils.toString(result);
final String expectedResult = "{"
+ "\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
+ "\"PropertyInt16\":32767,"
+ "\"PropertyString\":\"First Resource - positive values\","
+ "\"PropertyBoolean\":true,"
+ "\"PropertyByte\":255,"
+ "\"PropertySByte\":127,"
+ "\"PropertyInt32\":2147483647,"
+ "\"PropertyInt64\":\"" + Long.MAX_VALUE + "\","
+ "\"PropertySingle\":1.79E20,"
+ "\"PropertyDouble\":-1.79E19,"
+ "\"PropertyDecimal\":\"34\","
+ "\"PropertyBinary\":\"ASNFZ4mrze8=\","
+ "\"PropertyDate\":\"2012-12-03\","
+ "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\","
+ "\"PropertyDuration\":\"PT6S\","
+ "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\","
+ "\"PropertyTimeOfDay\":\"03:26:05\""
+ "}";
Assert.assertEquals(expectedResult, resultString);
}
@Test
public void entityCollAllPrimIEEE754Compatible() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
EntitySerializerOptions.with()
.contextURL(ContextURL.with().serviceRoot(URI.create("http://host/service/"))
.entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
.setIEEE754Compatible(true)
.build()).getContent();
final String resultString = IOUtils.toString(result);
final String expectedResult = "{"
+ "\"@odata.context\":\"http://host/service/$metadata#ESCollAllPrim/$entity\","
+ "\"PropertyInt16\":1,"
+ "\"CollPropertyString\":"
+ "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
+ "\"CollPropertyBoolean\":[true,false,true],"
+ "\"CollPropertyByte\":[50,200,249],"
+ "\"CollPropertySByte\":[-120,120,126],"
+ "\"CollPropertyInt16\":[1000,2000,30112],"
+ "\"CollPropertyInt32\":[23232323,11223355,10000001],"
+ "\"CollPropertyInt64\":[\"929292929292\",\"333333333333\",\"444444444444\"],"
+ "\"CollPropertySingle\":[1790.0,26600.0,3210.0],"
+ "\"CollPropertyDouble\":[-17900.0,-2.78E7,3210.0],"
+ "\"CollPropertyDecimal\":[\"12\",\"-2\",\"1234\"],"
+ "\"CollPropertyBinary\":[\"q83v\",\"ASNF\",\"VGeJ\"],"
+ "\"CollPropertyDate\":[\"1958-12-03\",\"1999-08-05\",\"2013-06-25\"],"
+ "\"CollPropertyDateTimeOffset\":[\"2015-08-12T03:08:34Z\",\"1970-03-28T12:11:10Z\","
+ "\"1948-02-17T09:09:09Z\"],"
+ "\"CollPropertyDuration\":[\"PT13S\",\"PT5H28M0S\",\"PT1H0S\"],"
+ "\"CollPropertyGuid\":[\"ffffff67-89ab-cdef-0123-456789aaaaaa\",\"eeeeee67-89ab-cdef-0123-456789bbbbbb\","
+ "\"cccccc67-89ab-cdef-0123-456789cccccc\"],"
+ "\"CollPropertyTimeOfDay\":[\"04:14:13\",\"23:59:59\",\"01:12:33\"]"
+ "}";
Assert.assertEquals(expectedResult, resultString);
}
@Test
public void primitiveCollectionPropertyIEEE754CompatibleInt64() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("CollPropertyInt64");
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
final String resultString = IOUtils.toString(serializer
.primitiveCollection((EdmPrimitiveType) edmProperty.getType(), property,
PrimitiveSerializerOptions.with()
.contextURL(ContextURL.with()
.entitySet(edmEntitySet).keyPath("1").navOrPropertyPath(edmProperty.getName()).build())
.setIEEE754Compatible(true)
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESCollAllPrim(1)/CollPropertyInt64\","
+ "\"value\":[\"929292929292\",\"333333333333\",\"444444444444\"]}",
resultString);
}
@Test
public void primitiveCollectionPropertyIEEE754CompatibleDecimal() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("CollPropertyDecimal");
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
final String resultString = IOUtils.toString(serializer
.primitiveCollection((EdmPrimitiveType) edmProperty.getType(), property,
PrimitiveSerializerOptions.with()
.contextURL(ContextURL.with()
.entitySet(edmEntitySet).keyPath("1").navOrPropertyPath(edmProperty.getName()).build())
.setIEEE754Compatible(true)
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESCollAllPrim(1)/CollPropertyDecimal\","
+ "\"value\":[\"12\",\"-2\",\"1234\"]}",
resultString);
}
@Test
public void primitivePropertyIEEE754CompatibleInt64() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyInt64");
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
final String resultString = IOUtils.toString(serializer
.primitive((EdmPrimitiveType) edmProperty.getType(), property,
PrimitiveSerializerOptions.with()
.contextURL(ContextURL.with()
.entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName()).build())
.setIEEE754Compatible(true)
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESAllPrim(32767)/PropertyInt64\","
+ "\"value\":\"" + Long.MAX_VALUE + "\"}",
resultString);
}
@Test
public void primitivePropertyIEEE754CompatibleDecimal() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyDecimal");
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
final String resultString = IOUtils.toString(serializer
.primitive((EdmPrimitiveType) edmProperty.getType(), property,
PrimitiveSerializerOptions.with()
.contextURL(ContextURL.with()
.entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName()).build())
.setIEEE754Compatible(true)
.build()).getContent());
Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESAllPrim(32767)/PropertyDecimal\","
+ "\"value\":\"34\"}",
resultString);
}
@Test
public void entitySetAllPrimIEEE754CompatibleCount() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
EntityCollection entitySet = data.readAll(edmEntitySet);
entitySet.setCount(entitySet.getEntities().size());
entitySet.setNext(URI.create("/next"));
CountOption countOption = Mockito.mock(CountOption.class);
Mockito.when(countOption.getValue()).thenReturn(true);
InputStream result = serializer.entityCollection(metadata, edmEntitySet.getEntityType(), entitySet,
EntityCollectionSerializerOptions.with()
.setIEEE754Compatible(true)
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
.count(countOption)
.build()).getContent();
final String resultString = IOUtils.toString(result);
Assert.assertThat(resultString, CoreMatchers.startsWith("{"
+ "\"@odata.context\":\"$metadata#ESAllPrim\","
+ "\"@odata.count\":\"3\",\"value\":["));
Assert.assertThat(resultString, CoreMatchers.endsWith("],"
+ "\"@odata.nextLink\":\"/next\"}"));
int count = 0;
int index = -1;
while ((index = resultString.indexOf("PropertyInt16\":", ++index)) > 0) {
count++;
}
Assert.assertEquals(3, count);
}
@Test
public void entitySetAllPrimReferenceIEEE754CompatibleCount() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
EntityCollection entitySet = data.readAll(edmEntitySet);
entitySet.setCount(entitySet.getEntities().size());
entitySet.setNext(URI.create("/next"));
CountOption countOption = Mockito.mock(CountOption.class);
Mockito.when(countOption.getValue()).thenReturn(true);
InputStream result = serializer.referenceCollection(metadata, edmEntitySet, entitySet,
ReferenceCollectionSerializerOptions.with()
.setIEEE754Compatible(true)
.contextURL(ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build())
.count(countOption)
.build()).getContent();
final String resultString = IOUtils.toString(result);
Assert.assertThat(resultString, CoreMatchers.startsWith("{"
+ "\"@odata.context\":\"$metadata#Collection($ref)\","
+ "\"@odata.count\":\"3\",\"value\":["));
Assert.assertThat(resultString, CoreMatchers.endsWith("],"
+ "\"@odata.nextLink\":\"/next\"}"));
int count = 0;
int index = -1;
while ((index = resultString.indexOf("ESAllPrim(", ++index)) > 0) {
count++;
}
Assert.assertEquals(3, count);
}
} }