diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java index 819aab7d1..936569e1b 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java @@ -28,6 +28,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.math.BigDecimal; import java.net.URI; import java.util.Collections; import java.util.Iterator; @@ -44,6 +45,7 @@ import org.apache.olingo.client.api.communication.request.cud.UpdateType; import org.apache.olingo.client.api.communication.request.retrieve.EdmMetadataRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest; +import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataServiceDocumentRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataValueRequest; import org.apache.olingo.client.api.communication.request.retrieve.XMLMetadataRequest; @@ -75,11 +77,27 @@ import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.fit.AbstractBaseTestITCase; import org.apache.olingo.fit.tecsvc.TecSvcConst; +import org.junit.Ignore; import org.junit.Test; public class BasicITCase extends AbstractBaseTestITCase { - + + private static final String CONTENT_TYPE_JSON_IEEE754_COMPATIBLE = "application/json;odata.metadata=minimal;" + + "IEEE754Compatible=true"; + private static final String SERVICE_NAMESPACE = "olingo.odata.test1"; + private static final String ET_ALL_PRIM_NAME = "ETAllPrim"; + private static final FullQualifiedName ET_ALL_PRIM = new FullQualifiedName(SERVICE_NAMESPACE, ET_ALL_PRIM_NAME); + + private static final String PROPERTY_INT16 = "PropertyInt16"; + private static final String PROPERTY_INT64 = "PropertyInt64"; + private static final String PROPERTY_DECIMAL = "PropertyDecimal"; + private static final String PROPERTY_COMP_ALL_PRIM = "PropertyCompAllPrim"; + private static final String NAV_PROPERTY_ET_TWO_PRIM_ONE = "NavPropertyETTwoPrimOne"; + private static final String SERVICE_URI = TecSvcConst.BASE_URI; + private static final String ES_ALL_PRIM = "ESAllPrim"; + private static final String ES_TWO_PRIM = "ESTwoPrim"; + private static final String ES_KEY_NAV = "ESKeyNav"; @Test public void readServiceDocument() { @@ -376,7 +394,7 @@ public class BasicITCase extends AbstractBaseTestITCase { ClientEntity newEntity = factory.newEntity(new FullQualifiedName("olingo.odata.test1", "ETAllPrim")); newEntity.getProperties().add(factory.newPrimitiveProperty("PropertyInt64", factory.newPrimitiveValueBuilder().buildInt32(42))); - newEntity.addLink(factory.newEntityNavigationLink("NavPropertyETTwoPrimOne", + newEntity.addLink(factory.newEntityNavigationLink(NAV_PROPERTY_ET_TWO_PRIM_ONE, client.newURIBuilder(SERVICE_URI) .appendEntitySetSegment("ESTwoPrim") .appendKeySegment(32766) @@ -916,7 +934,173 @@ public class BasicITCase extends AbstractBaseTestITCase { .get("PropertyInt16") .hasNullValue()); } + + @Test + public void createEntityWithIEEE754CompatibleParameter() { + final ODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + client.getConfiguration().setDefaultPubFormat(ODataFormat.JSON); + final ClientObjectFactory of = client.getObjectFactory(); + final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_ALL_PRIM).build(); + final URI linkURI = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_TWO_PRIM) + .appendKeySegment(32767).build(); + + final ClientEntity newEntity = of.newEntity(ET_ALL_PRIM); + newEntity.getProperties().add(of.newPrimitiveProperty(PROPERTY_INT64, + of.newPrimitiveValueBuilder().buildString("" + Long.MAX_VALUE))); + newEntity.getProperties().add(of.newPrimitiveProperty(PROPERTY_DECIMAL, + of.newPrimitiveValueBuilder().buildString("" + 34L))); + newEntity.addLink(of.newEntityNavigationLink(NAV_PROPERTY_ET_TWO_PRIM_ONE, linkURI)); + + final ODataEntityCreateRequest request = client.getCUDRequestFactory() + .getEntityCreateRequest(uri, newEntity); + request.setContentType(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE); + request.setAccept(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE); + final ODataEntityCreateResponse response = request.execute(); + + assertEquals(Long.MAX_VALUE, response.getBody().getProperty(PROPERTY_INT64).getPrimitiveValue().toValue()); + assertEquals(BigDecimal.valueOf(34), response.getBody().getProperty(PROPERTY_DECIMAL) + .getPrimitiveValue().toValue()); + } + + @Test + public void createEntityInt64AndDecimalAsStringWithoutIEEE754ComaptibleParameter() { + final ODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + client.getConfiguration().setDefaultPubFormat(ODataFormat.JSON); + final ClientObjectFactory of = client.getObjectFactory(); + final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_ALL_PRIM).build(); + final URI linkURI = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_TWO_PRIM) + .appendKeySegment(32767).build(); + + final ClientEntity newEntity = of.newEntity(ET_ALL_PRIM); + newEntity.getProperties().add(of.newPrimitiveProperty(PROPERTY_INT64, + of.newPrimitiveValueBuilder().buildString("" + Long.MAX_VALUE))); + newEntity.getProperties().add(of.newPrimitiveProperty(PROPERTY_DECIMAL, + of.newPrimitiveValueBuilder().buildString("" + 34L))); + newEntity.addLink(of.newEntityNavigationLink(NAV_PROPERTY_ET_TWO_PRIM_ONE, linkURI)); + + final ODataEntityCreateRequest request = client.getCUDRequestFactory() + .getEntityCreateRequest(uri, newEntity); + try { + request.execute(); + fail(); + } catch(ODataClientErrorException e) { + assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), e.getStatusLine().getStatusCode()); + } + } + + @Test + public void readESAllPrimCollectionWithIEEE754CompatibleParameter() { + final ODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_ALL_PRIM) + .orderBy(PROPERTY_INT16) + .build(); + + final ODataEntitySetRequest request = client.getRetrieveRequestFactory().getEntitySetRequest(uri); + request.setAccept(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE); + final ODataRetrieveResponse response = request.execute(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + final List entities = response.getBody().getEntities(); + assertEquals(3, entities.size()); + + ClientEntity entity = entities.get(0); + assertEquals(-32768, entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + assertEquals(Long.MIN_VALUE, entity.getProperty(PROPERTY_INT64).getPrimitiveValue().toValue()); + assertEquals(BigDecimal.valueOf(-34), entity.getProperty(PROPERTY_DECIMAL).getPrimitiveValue().toValue()); + + entity = entities.get(1); + assertEquals(0, entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + assertEquals(0L, entity.getProperty(PROPERTY_INT64).getPrimitiveValue().toValue()); + assertEquals(BigDecimal.valueOf(0), entity.getProperty(PROPERTY_DECIMAL).getPrimitiveValue().toValue()); + + entity = entities.get(2); + assertEquals(32767, entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + assertEquals(Long.MAX_VALUE, entity.getProperty(PROPERTY_INT64).getPrimitiveValue().toValue()); + assertEquals(BigDecimal.valueOf(34), entity.getProperty(PROPERTY_DECIMAL).getPrimitiveValue().toValue()); + } + + @Test + public void readESKeyNavCheckComplexPropertyWithIEEE754CompatibleParameter() { + final ODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_KEY_NAV).appendKeySegment(1).build(); + + final ODataEntityRequest request = client.getRetrieveRequestFactory().getEntityRequest(uri); + request.setAccept(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE); + final ODataRetrieveResponse response = request.execute(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertEquals(1, response.getBody().getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + + assertEquals(BigDecimal.valueOf(34), response.getBody().getProperty(PROPERTY_COMP_ALL_PRIM) + .getComplexValue() + .get(PROPERTY_DECIMAL) + .getPrimitiveValue() + .toValue()); + + assertEquals(Long.MAX_VALUE, response.getBody().getProperty(PROPERTY_COMP_ALL_PRIM) + .getComplexValue() + .get(PROPERTY_INT64) + .getPrimitiveValue() + .toValue()); + } + + @Test + public void readESKEyNavComplexPropertyWithIEEE754CompatibleParameter() { + final ODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_KEY_NAV) + .appendKeySegment(1) + .appendNavigationSegment(PROPERTY_COMP_ALL_PRIM) + .build(); + ODataPropertyRequest request = client.getRetrieveRequestFactory().getPropertyRequest(uri); + request.setAccept(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE); + final ODataRetrieveResponse response = request.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + assertEquals(BigDecimal.valueOf(34), response.getBody().getComplexValue() + .get(PROPERTY_DECIMAL) + .getPrimitiveValue() + .toValue()); + assertEquals(Long.MAX_VALUE, response.getBody().getComplexValue() + .get(PROPERTY_INT64) + .getPrimitiveValue() + .toValue()); + } + + @Test + @Ignore + public void readEdmInt64PropertyWithIEEE754ComaptibleParameter() { + final ODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_KEY_NAV) + .appendKeySegment(1) + .appendPropertySegment(PROPERTY_COMP_ALL_PRIM) + .appendPropertySegment(PROPERTY_INT64) + .build(); + ODataPropertyRequest request = client.getRetrieveRequestFactory().getPropertyRequest(uri); + request.setAccept(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE); + final ODataRetrieveResponse response = request.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + assertEquals(Long.MAX_VALUE, response.getBody().getPrimitiveValue().toValue()); + } + + @Test + @Ignore + public void readEdmDecimalPropertyWithIEEE754ComaptibleParameter() { + final ODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_KEY_NAV) + .appendKeySegment(1) + .appendPropertySegment(PROPERTY_COMP_ALL_PRIM) + .appendPropertySegment(PROPERTY_DECIMAL) + .build(); + ODataPropertyRequest request = client.getRetrieveRequestFactory().getPropertyRequest(uri); + request.setAccept(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE); + final ODataRetrieveResponse response = request.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + assertEquals(BigDecimal.valueOf(34), response.getBody().getPrimitiveValue().toValue()); + } + @Override protected ODataClient getClient() { ODataClient odata = ODataClientFactory.getClient(); diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicHttpITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicHttpITCase.java index 1a66f11dd..dc32808a4 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicHttpITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicHttpITCase.java @@ -19,15 +19,20 @@ package org.apache.olingo.fit.tecsvc.http; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import org.apache.olingo.client.api.ODataClient; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.http.HttpHeader; +import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.fit.AbstractBaseTestITCase; import org.apache.olingo.fit.tecsvc.TecSvcConst; +import org.apache.olingo.server.core.deserializer.batch.BufferedReaderIncludingLineEndings; import org.junit.Test; public class BasicHttpITCase extends AbstractBaseTestITCase { @@ -116,7 +121,54 @@ public class BasicHttpITCase extends AbstractBaseTestITCase { String v = connection.getHeaderField(HttpHeader.ODATA_VERSION); assertEquals("4.0", v); } - + + @Test + public void testIEEE754ParameterContentNegotiation() throws Exception { + final URL url = new URL(SERVICE_URI + "/ESAllPrim(32767)?$format=application/json;IEEE754Compatible=true"); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json;IEEE754Compatible=false"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + assertEquals(ContentType.create("application/json;IEEE754Compatible=true;odata.metadata=minimal"), + ContentType.create(connection.getContentType())); + final String content = inputStreamToString(connection.getInputStream()); + + assertTrue(content.contains("\"PropertyDecimal\":\"34\"")); + assertTrue(content.contains("\"PropertyInt64\":\"9223372036854775807\"")); + } + + @Test + public void testIEEE754ParameterViaAcceptHeader() throws Exception { + final URL url = new URL(SERVICE_URI + "/ESAllPrim(32767)"); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json;IEEE754Compatible=true"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + assertEquals(ContentType.create("application/json;IEEE754Compatible=true;odata.metadata=minimal"), + ContentType.create(connection.getContentType())); + final String content = inputStreamToString(connection.getInputStream()); + + assertTrue(content.contains("\"PropertyDecimal\":\"34\"")); + assertTrue(content.contains("\"PropertyInt64\":\"9223372036854775807\"")); + } + + private String inputStreamToString(final InputStream in) throws Exception { + final BufferedReaderIncludingLineEndings reader = new BufferedReaderIncludingLineEndings(new InputStreamReader(in)); + final StringBuffer buffer = new StringBuffer(); + String current; + + while((current = reader.readLine()) != null) { + buffer.append(current); + } + + reader.close(); + return buffer.toString(); + } + @Override protected ODataClient getClient() { return null; diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java index e1dddb8f9..7f2273cfc 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java @@ -41,14 +41,13 @@ import org.apache.olingo.commons.api.edm.EdmNavigationPropertyBinding; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.format.ContentType; -import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; import org.apache.olingo.commons.core.edm.primitivetype.EdmStream; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataApplicationException; -import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ODataLibraryException; +import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.deserializer.DeserializerException; import org.apache.olingo.server.api.deserializer.DeserializerException.MessageKeys; @@ -440,7 +439,7 @@ public class DataRequest extends ServiceRequest { handler.deleteReference(DataRequest.this, new URI(id), getETag(), new NoContentResponse( getServiceMetaData(), response)); } catch (URISyntaxException e) { - throw new DeserializerException("failed to read $id", e, MessageKeys.UNKOWN_CONTENT); + throw new DeserializerException("failed to read $id", e, MessageKeys.UNKNOWN_CONTENT); } } } else if (isPUT()) { diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java index 42a275df0..0cf4ff270 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java @@ -121,10 +121,10 @@ public class PropertyResponse extends ServiceResponse { throws SerializerException { if(this.collection) { this.response.setContent( - this.serializer.primitiveCollection(type, property, this.primitiveOptions).getContent()); + this.serializer.primitiveCollection(metadata, type, property, this.primitiveOptions).getContent()); } else { this.response.setContent( - this.serializer.primitive(type, property, this.primitiveOptions).getContent()); + this.serializer.primitive(metadata, type, property, this.primitiveOptions).getContent()); } writeOK(this.responseContentType.toContentTypeString()); close(); diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java index ebb1575de..407510dd8 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java @@ -51,7 +51,7 @@ public class ServiceDocumentResponse extends ServiceResponse { public void writeServiceDocument(String serviceRoot) throws ODataLibraryException { assert (!isClosed()); - this.response.setContent(this.serializer.serviceDocument(metadata.getEdm(), serviceRoot).getContent()); + this.response.setContent(this.serializer.serviceDocument(metadata, serviceRoot).getContent()); writeOK(this.responseContentType.toContentTypeString()); close(); } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java index 67c8875e5..9c3c76337 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java @@ -51,12 +51,15 @@ import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.edm.EdmTypeDefinition; import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; import org.apache.olingo.server.api.deserializer.DeserializerException; +import org.apache.olingo.server.api.deserializer.DeserializerException.MessageKeys; import org.apache.olingo.server.api.deserializer.DeserializerResult; import org.apache.olingo.server.api.deserializer.ODataDeserializer; import org.apache.olingo.server.core.deserializer.DeserializerResultImpl; import org.apache.olingo.server.core.deserializer.helper.ExpandTreeBuilder; import org.apache.olingo.server.core.deserializer.helper.ExpandTreeBuilderImpl; + import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParser; @@ -72,8 +75,12 @@ public class ODataJsonDeserializer implements ODataDeserializer { private static final String ODATA_ANNOTATION_MARKER = "@"; private static final String ODATA_CONTROL_INFORMATION_PREFIX = "@odata."; - + private static final EdmPrimitiveType EDM_INT64 = EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64); + private static final EdmPrimitiveType EDM_DECIMAL = EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal); + private final boolean isIEEE754Compatible; + public ODataJsonDeserializer(final ContentType contentType) { + isIEEE754Compatible = isODataIEEE754Compatible(contentType); } @Override @@ -666,8 +673,17 @@ public class ODataJsonDeserializer implements ODataDeserializer { EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) type; checkJsonTypeBasedOnPrimitiveType(name, edmPrimitiveType.getName(), jsonNode); Class javaClass = getJavaClassForPrimitiveType(mapping, edmPrimitiveType); - return edmPrimitiveType.valueOfString(jsonNode.asText(), - isNullable, maxLength, precision, scale, isUnicode, javaClass); + String jsonNodeAsText = jsonNode.asText(); + + if (isIEEE754Compatible && (edmPrimitiveType.equals(EDM_INT64) || edmPrimitiveType.equals(EDM_DECIMAL))) { + if(jsonNodeAsText.length() == 0) { + throw new DeserializerException("IEEE754Compatible values must not be of length 0", + MessageKeys.INVALID_NULL_PROPERTY, name); + } + } + + return edmPrimitiveType.valueOfString(jsonNodeAsText, isNullable, maxLength, precision, scale, isUnicode, + javaClass); } catch (EdmPrimitiveTypeException e) { throw new DeserializerException( "Invalid value: " + jsonNode.asText() + " for property: " + name, e, @@ -734,20 +750,33 @@ public class ODataJsonDeserializer implements ODataDeserializer { + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, propertyName); } break; - // Numbers + // Numbers (must be numbers) case Int16: case Int32: - case Int64: case Byte: case SByte: case Single: case Double: - case Decimal: if (!jsonNode.isNumber()) { throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, propertyName); } break; + case Int64: + case Decimal: + // Numbers (eighter numers or string) + if(isIEEE754Compatible) { + if (!jsonNode.isTextual()) { + throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind + + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, propertyName); + } + } else { + if (!jsonNode.isNumber()) { + throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind + + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, propertyName); + } + } + break; // Strings case String: case Binary: @@ -851,4 +880,10 @@ public class ODataJsonDeserializer implements ODataDeserializer { DeserializerException.MessageKeys.UNKNOWN_CONTENT); } } + + private boolean isODataIEEE754Compatible(final ContentType contentType) { + return contentType.getParameters().containsKey("ieee754compatible") + && Boolean.TRUE.toString().toLowerCase().equals( + contentType.getParameters().get("ieee754compatible").toLowerCase()); + } } diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/AbstractODataDeserializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/AbstractODataDeserializerTest.java index e03b32cca..7030b1352 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/AbstractODataDeserializerTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/AbstractODataDeserializerTest.java @@ -31,6 +31,9 @@ import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; public class AbstractODataDeserializerTest { protected static final ContentType CONTENT_TYPE_JSON = ODataFormat.JSON.getContentType(); + protected static final ContentType CONTENT_TYPE_JSON_IEEE754Compatible = + ContentType.parse("application/json;odata.format=minimal;IEEE754Compatible=true"); + protected static final Edm edm = OData.newInstance().createServiceMetadata( new EdmTechProvider(), Collections. emptyList()).getEdm(); diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java index 01ec4b500..468446126 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java @@ -52,7 +52,6 @@ import org.apache.olingo.server.api.deserializer.DeserializerException; import org.apache.olingo.server.api.deserializer.ODataDeserializer; import org.apache.olingo.server.api.edmx.EdmxReference; import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; -import org.junit.Ignore; import org.junit.Test; public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTest { @@ -1414,9 +1413,8 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe } @Test - @Ignore public void ieee754Compatible() throws Exception { - ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON); + ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON_IEEE754Compatible); String entityString = "{\"PropertyInt16\":32767," + "\"PropertyString\":\"First Resource - positive values\"," + @@ -1440,7 +1438,86 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe .entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity(); assertEquals(9223372036854775807L, entity.getProperty("PropertyInt64").asPrimitive()); - assertEquals(34, entity.getProperty("PropertyDecimal").asPrimitive()); + assertEquals(BigDecimal.valueOf(34), entity.getProperty("PropertyDecimal").asPrimitive()); + } + + @Test + public void ieee754CompatibleNull() throws Exception { + ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON_IEEE754Compatible); + String entityString = + "{\"PropertyInt16\":32767," + + "\"PropertyString\":\"First Resource - positive values\"," + + "\"PropertyBoolean\":null," + + "\"PropertyByte\":255," + + "\"PropertySByte\":127," + + "\"PropertyInt32\":2147483647," + + "\"PropertyInt64\":null," + + "\"PropertySingle\":1.79E20," + + "\"PropertyDouble\":-1.79E19," + + "\"PropertyDecimal\":null," + + "\"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(); + + assertTrue(entity.getProperty("PropertyInt64").isNull()); + assertTrue(entity.getProperty("PropertyDecimal").isNull()); + } + + @Test(expected=DeserializerException.class) + public void ieee754CompatibleEmptyString() throws Exception { + ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON_IEEE754Compatible); + String entityString = + "{\"PropertyInt16\":32767," + + "\"PropertyString\":\"First Resource - positive values\"," + + "\"PropertyBoolean\":null," + + "\"PropertyByte\":255," + + "\"PropertySByte\":127," + + "\"PropertyInt32\":2147483647," + + "\"PropertyInt64\":\"\"," + + "\"PropertySingle\":1.79E20," + + "\"PropertyDouble\":-1.79E19," + + "\"PropertyDecimal\":\" \"," + + "\"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()); + deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity(); + } + + @Test(expected=DeserializerException.class) + public void ieee754CompatibleNullAsString() throws Exception { + ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON_IEEE754Compatible); + String entityString = + "{\"PropertyInt16\":32767," + + "\"PropertyString\":\"First Resource - positive values\"," + + "\"PropertyBoolean\":null," + + "\"PropertyByte\":255," + + "\"PropertySByte\":127," + + "\"PropertyInt32\":2147483647," + + "\"PropertyInt64\":\"null\"," + + "\"PropertySingle\":1.79E20," + + "\"PropertyDouble\":-1.79E19," + + "\"PropertyDecimal\":\"null\"," + + "\"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()); + deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity(); } private void checkPropertyJsonType(final String entityString) throws DeserializerException { diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java index a2a1b3745..c7d1782fa 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java @@ -36,11 +36,7 @@ import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmPrimitiveType; import org.apache.olingo.commons.api.edm.EdmProperty; -<<<<<<< HEAD -======= -import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.format.ContentType; ->>>>>>> [OLINGO-690] ODataSerializer and ODataDeserializer are created by contentType instead of ODataFormat import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.edmx.EdmxReference; @@ -326,6 +322,7 @@ public class ODataJsonSerializerTest { .entityCollection(metadata, edmEntitySet.getEntityType(), entitySet, EntityCollectionSerializerOptions.with() .contextURL(ContextURL.with().entitySet(edmEntitySet).build()).build()).getContent(); + final String resultString = IOUtils.toString(result); final String expectedResult = "{\"value\":[" + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}," @@ -809,6 +806,7 @@ public class ODataJsonSerializerTest { final String resultString = IOUtils.toString(result); final String expectedResult = "{" + "\"@odata.context\":\"$metadata#ESAllPrim/$entity\"," + + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," + "\"PropertyInt16\":32767," + "\"PropertyString\":\"First Resource - positive values\"," + "\"PropertyBoolean\":true," @@ -841,6 +839,7 @@ public class ODataJsonSerializerTest { final String resultString = IOUtils.toString(result); final String expectedResult = "{" + "\"@odata.context\":\"http://host/service/$metadata#ESCollAllPrim/$entity\"," + + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," + "\"PropertyInt16\":1," + "\"CollPropertyString\":" + "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"]," @@ -872,13 +871,14 @@ public class ODataJsonSerializerTest { final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName()); final String resultString = IOUtils.toString(serializerIEEECompatible - .primitiveCollection((EdmPrimitiveType) edmProperty.getType(), property, + .primitiveCollection(metadata, (EdmPrimitiveType) edmProperty.getType(), property, PrimitiveSerializerOptions.with() .contextURL(ContextURL.with() .entitySet(edmEntitySet).keyPath("1").navOrPropertyPath(edmProperty.getName()).build()) .build()).getContent()); Assert.assertEquals("{" + "\"@odata.context\":\"$metadata#ESCollAllPrim(1)/CollPropertyInt64\"," + + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," + "\"value\":[\"929292929292\",\"333333333333\",\"444444444444\"]}", resultString); } @@ -890,13 +890,14 @@ public class ODataJsonSerializerTest { final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName()); final String resultString = IOUtils.toString(serializerIEEECompatible - .primitiveCollection((EdmPrimitiveType) edmProperty.getType(), property, + .primitiveCollection(metadata, (EdmPrimitiveType) edmProperty.getType(), property, PrimitiveSerializerOptions.with() .contextURL(ContextURL.with() .entitySet(edmEntitySet).keyPath("1").navOrPropertyPath(edmProperty.getName()).build()) .build()).getContent()); Assert.assertEquals("{" + "\"@odata.context\":\"$metadata#ESCollAllPrim(1)/CollPropertyDecimal\"," + + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," + "\"value\":[\"12\",\"-2\",\"1234\"]}", resultString); } @@ -907,13 +908,14 @@ public class ODataJsonSerializerTest { 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(serializerIEEECompatible - .primitive((EdmPrimitiveType) edmProperty.getType(), property, + .primitive(metadata, (EdmPrimitiveType) edmProperty.getType(), property, PrimitiveSerializerOptions.with() .contextURL(ContextURL.with() .entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName()).build()) .build()).getContent()); Assert.assertEquals("{" + "\"@odata.context\":\"$metadata#ESAllPrim(32767)/PropertyInt64\"," + + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," + "\"value\":\"" + Long.MAX_VALUE + "\"}", resultString); } @@ -924,13 +926,14 @@ public class ODataJsonSerializerTest { 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(serializerIEEECompatible - .primitive((EdmPrimitiveType) edmProperty.getType(), property, + .primitive(metadata, (EdmPrimitiveType) edmProperty.getType(), property, PrimitiveSerializerOptions.with() .contextURL(ContextURL.with() .entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName()).build()) .build()).getContent()); Assert.assertEquals("{" + "\"@odata.context\":\"$metadata#ESAllPrim(32767)/PropertyDecimal\"," + + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," + "\"value\":\"34\"}", resultString); } @@ -952,6 +955,7 @@ public class ODataJsonSerializerTest { Assert.assertThat(resultString, CoreMatchers.startsWith("{" + "\"@odata.context\":\"$metadata#ESAllPrim\"," + + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," + "\"@odata.count\":\"3\",\"value\":[")); Assert.assertThat(resultString, CoreMatchers.endsWith("]," + "\"@odata.nextLink\":\"/next\"}")); @@ -981,6 +985,7 @@ public class ODataJsonSerializerTest { Assert.assertThat(resultString, CoreMatchers.startsWith("{" + "\"@odata.context\":\"$metadata#Collection($ref)\"," + + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," + "\"@odata.count\":\"3\",\"value\":[")); Assert.assertThat(resultString, CoreMatchers.endsWith("]," + "\"@odata.nextLink\":\"/next\"}")); diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentTest.java index 44607d8db..845197653 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentTest.java @@ -50,7 +50,7 @@ public class ServiceDocumentTest { ODataSerializer serializer = server.createSerializer(ODataFormat.JSON.getContentType()); assertNotNull(serializer); - InputStream result = serializer.serviceDocument(metadata.getEdm(), serviceRoot).getContent(); + InputStream result = serializer.serviceDocument(metadata, serviceRoot).getContent(); assertNotNull(result); final String jsonString = IOUtils.toString(result);