diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/PropertyRetrieveTestITCase.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/PropertyRetrieveTestITCase.java index 2e495dcd0..a38b403f1 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/PropertyRetrieveTestITCase.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/PropertyRetrieveTestITCase.java @@ -18,14 +18,19 @@ */ package org.apache.olingo.client.core.it.v3; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.util.List; import org.apache.olingo.client.api.communication.ODataClientErrorException; 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.response.ODataRetrieveResponse; -import org.apache.olingo.client.api.uri.CommonURIBuilder; +import org.apache.olingo.client.api.uri.v3.URIBuilder; import org.apache.olingo.commons.api.domain.CommonODataEntity; -import org.apache.olingo.commons.api.domain.CommonODataEntitySet; import org.apache.olingo.commons.api.domain.ODataCollectionValue; import org.apache.olingo.commons.api.domain.ODataComplexValue; import org.apache.olingo.commons.api.domain.ODataPrimitiveValue; @@ -33,17 +38,12 @@ import org.apache.olingo.commons.api.domain.v3.ODataEntity; import org.apache.olingo.commons.api.domain.v3.ODataEntitySet; import org.apache.olingo.commons.api.domain.v3.ODataProperty; import org.apache.olingo.commons.api.format.ODataFormat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import org.junit.Test; public class PropertyRetrieveTestITCase extends AbstractTestITCase { - private void retreivePropertyTest(final ODataFormat format, String entitySegment, String structuralSegment) { - final CommonURIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). + private void retrievePropertyTest(final ODataFormat format, String entitySegment, String structuralSegment) { + final URIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). appendEntitySetSegment(entitySegment).appendPropertySegment(structuralSegment); final ODataPropertyRequest req = client.getRetrieveRequestFactory(). getPropertyRequest(uriBuilder.build()); @@ -75,48 +75,48 @@ public class PropertyRetrieveTestITCase extends AbstractTestITCase { @Test public void jsonRetrieveProperty() { //Primitive types - retreivePropertyTest(ODataFormat.JSON, "Customer(-10)", "Name"); - retreivePropertyTest(ODataFormat.JSON, "Customer(-10)", "CustomerId"); - retreivePropertyTest(ODataFormat.JSON, "Message(FromUsername='1',MessageId=-10)", "Sent"); - retreivePropertyTest(ODataFormat.JSON, "Message(FromUsername='1',MessageId=-10)", "IsRead"); + retrievePropertyTest(ODataFormat.JSON, "Customer(-10)", "Name"); + retrievePropertyTest(ODataFormat.JSON, "Customer(-10)", "CustomerId"); + retrievePropertyTest(ODataFormat.JSON, "Message(FromUsername='1',MessageId=-10)", "Sent"); + retrievePropertyTest(ODataFormat.JSON, "Message(FromUsername='1',MessageId=-10)", "IsRead"); //Collection of Complex types - retreivePropertyTest(ODataFormat.JSON, "Customer(-10)", "BackupContactInfo"); + retrievePropertyTest(ODataFormat.JSON, "Customer(-10)", "BackupContactInfo"); //Collection of primitives - retreivePropertyTest(ODataFormat.JSON, "Customer(-10)/PrimaryContactInfo", "EmailBag"); + retrievePropertyTest(ODataFormat.JSON, "Customer(-10)/PrimaryContactInfo", "EmailBag"); //complex types - retreivePropertyTest(ODataFormat.JSON, "Order(-9)", "Concurrency"); + retrievePropertyTest(ODataFormat.JSON, "Order(-9)", "Concurrency"); } //test with json full metadata @Test public void jsonFullMetadataRetrieveProperty() { //primitive types - retreivePropertyTest(ODataFormat.JSON_FULL_METADATA, "Customer(-10)", "Name"); - retreivePropertyTest(ODataFormat.JSON_FULL_METADATA, "Customer(-10)", "CustomerId"); - retreivePropertyTest(ODataFormat.JSON_FULL_METADATA, "Message(FromUsername='1',MessageId=-10)", "Sent"); - retreivePropertyTest(ODataFormat.JSON_FULL_METADATA, "Message(FromUsername='1',MessageId=-10)", "IsRead"); + retrievePropertyTest(ODataFormat.JSON_FULL_METADATA, "Customer(-10)", "Name"); + retrievePropertyTest(ODataFormat.JSON_FULL_METADATA, "Customer(-10)", "CustomerId"); + retrievePropertyTest(ODataFormat.JSON_FULL_METADATA, "Message(FromUsername='1',MessageId=-10)", "Sent"); + retrievePropertyTest(ODataFormat.JSON_FULL_METADATA, "Message(FromUsername='1',MessageId=-10)", "IsRead"); //Collection of Complex types - retreivePropertyTest(ODataFormat.JSON_FULL_METADATA, "Customer(-10)", "BackupContactInfo"); + retrievePropertyTest(ODataFormat.JSON_FULL_METADATA, "Customer(-10)", "BackupContactInfo"); //Collection of primitives - retreivePropertyTest(ODataFormat.JSON_FULL_METADATA, "Customer(-10)/PrimaryContactInfo", "EmailBag"); + retrievePropertyTest(ODataFormat.JSON_FULL_METADATA, "Customer(-10)/PrimaryContactInfo", "EmailBag"); //Complex types - retreivePropertyTest(ODataFormat.JSON_FULL_METADATA, "Order(-9)", "Concurrency"); + retrievePropertyTest(ODataFormat.JSON_FULL_METADATA, "Order(-9)", "Concurrency"); } // json with no metadata @Test public void jsonNoMetadataRetrieveProperty() { //primitive types - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "Name"); - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "CustomerId"); - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Message(FromUsername='1',MessageId=-10)", "Sent"); - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Message(FromUsername='1',MessageId=-10)", "IsRead"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "Name"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "CustomerId"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Message(FromUsername='1',MessageId=-10)", "Sent"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Message(FromUsername='1',MessageId=-10)", "IsRead"); //Collection of Complex types - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "BackupContactInfo"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "BackupContactInfo"); //Collection of Primitives - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)/PrimaryContactInfo", "EmailBag"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)/PrimaryContactInfo", "EmailBag"); //Complex types - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Order(-9)", "Concurrency"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Order(-9)", "Concurrency"); } // json with minimla metadata @@ -124,55 +124,55 @@ public class PropertyRetrieveTestITCase extends AbstractTestITCase { @Test public void jsonmininalRetrieveProperty() { //primitive types - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "Name"); - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "CustomerId"); - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Message(FromUsername='1',MessageId=-10)", "Sent"); - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Message(FromUsername='1',MessageId=-10)", "IsRead"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "Name"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "CustomerId"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Message(FromUsername='1',MessageId=-10)", "Sent"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Message(FromUsername='1',MessageId=-10)", "IsRead"); //Collection of complex types - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "BackupContactInfo"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)", "BackupContactInfo"); //Collection of primitives - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)/PrimaryContactInfo", "EmailBag"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Customer(-10)/PrimaryContactInfo", "EmailBag"); //Complex types - retreivePropertyTest(ODataFormat.JSON_NO_METADATA, "Order(-9)", "Concurrency"); + retrievePropertyTest(ODataFormat.JSON_NO_METADATA, "Order(-9)", "Concurrency"); } // with xml header @Test public void xmlRetrieveProperty() { //primitive types - retreivePropertyTest(ODataFormat.XML, "Customer(-10)", "Name"); - retreivePropertyTest(ODataFormat.XML, "Customer(-10)", "CustomerId"); - retreivePropertyTest(ODataFormat.XML, "Message(FromUsername='1',MessageId=-10)", "Sent"); - retreivePropertyTest(ODataFormat.XML, "Message(FromUsername='1',MessageId=-10)", "IsRead"); + retrievePropertyTest(ODataFormat.XML, "Customer(-10)", "Name"); + retrievePropertyTest(ODataFormat.XML, "Customer(-10)", "CustomerId"); + retrievePropertyTest(ODataFormat.XML, "Message(FromUsername='1',MessageId=-10)", "Sent"); + retrievePropertyTest(ODataFormat.XML, "Message(FromUsername='1',MessageId=-10)", "IsRead"); //Collection of Complex types - retreivePropertyTest(ODataFormat.XML, "Customer(-10)", "BackupContactInfo"); + retrievePropertyTest(ODataFormat.XML, "Customer(-10)", "BackupContactInfo"); //Collection of primitives - retreivePropertyTest(ODataFormat.XML, "Customer(-10)/PrimaryContactInfo", "EmailBag"); + retrievePropertyTest(ODataFormat.XML, "Customer(-10)/PrimaryContactInfo", "EmailBag"); //Complex types - retreivePropertyTest(ODataFormat.XML, "Order(-9)", "Concurrency"); + retrievePropertyTest(ODataFormat.XML, "Order(-9)", "Concurrency"); } // with atom header @Test public void atomRetrieveProperty() { //primitive types - retreivePropertyTest(ODataFormat.XML, "Customer(-10)", "Name"); - retreivePropertyTest(ODataFormat.XML, "Customer(-10)", "CustomerId"); - retreivePropertyTest(ODataFormat.XML, "Message(FromUsername='1',MessageId=-10)", "Sent"); - retreivePropertyTest(ODataFormat.XML, "Message(FromUsername='1',MessageId=-10)", "IsRead"); + retrievePropertyTest(ODataFormat.XML, "Customer(-10)", "Name"); + retrievePropertyTest(ODataFormat.XML, "Customer(-10)", "CustomerId"); + retrievePropertyTest(ODataFormat.XML, "Message(FromUsername='1',MessageId=-10)", "Sent"); + retrievePropertyTest(ODataFormat.XML, "Message(FromUsername='1',MessageId=-10)", "IsRead"); //Collection of Complex types - retreivePropertyTest(ODataFormat.XML, "Customer(-10)", "BackupContactInfo"); + retrievePropertyTest(ODataFormat.XML, "Customer(-10)", "BackupContactInfo"); //Collection of primitives - retreivePropertyTest(ODataFormat.XML, "Customer(-10)/PrimaryContactInfo", "EmailBag"); + retrievePropertyTest(ODataFormat.XML, "Customer(-10)/PrimaryContactInfo", "EmailBag"); //complex types - retreivePropertyTest(ODataFormat.XML, "Order(-9)", "Concurrency"); + retrievePropertyTest(ODataFormat.XML, "Order(-9)", "Concurrency"); } // with invalid structural segment @Test public void invalidSegmentRetrieveProperty() { //primitive types - retreivePropertyTest(ODataFormat.XML, "Customers(-10)", "Name"); + retrievePropertyTest(ODataFormat.XML, "Customers(-10)", "Name"); } // with null pub format @@ -180,7 +180,7 @@ public class PropertyRetrieveTestITCase extends AbstractTestITCase { @Test public void nullSegmentRetrieveProperty() { //primitive types - retreivePropertyTest(null, "Customers(-10)", "Name"); + retrievePropertyTest(null, "Customers(-10)", "Name"); } // with null accept header format @@ -188,7 +188,7 @@ public class PropertyRetrieveTestITCase extends AbstractTestITCase { @Test public void nullAcceptRetrieveProperty() { //primitive types - retreivePropertyTest(ODataFormat.XML, "Customers(-10)", "Name"); + retrievePropertyTest(ODataFormat.XML, "Customers(-10)", "Name"); } // with json pub format and atom accept format @@ -196,7 +196,7 @@ public class PropertyRetrieveTestITCase extends AbstractTestITCase { @Test public void differentFormatAndAcceptRetrieveProperty() { // - retreivePropertyTest(ODataFormat.JSON_FULL_METADATA, "Customers(-10)", "Name"); + retrievePropertyTest(ODataFormat.JSON_FULL_METADATA, "Customers(-10)", "Name"); } //bad request 400 error. Message takes two keys @@ -204,22 +204,22 @@ public class PropertyRetrieveTestITCase extends AbstractTestITCase { @Test public void badRequestTest() { //primitive types - retreivePropertyTest(ODataFormat.JSON_FULL_METADATA, "Message(FromUsername='1')", "Sent"); + retrievePropertyTest(ODataFormat.JSON_FULL_METADATA, "Message(FromUsername='1')", "Sent"); } //navigation link of stream @Test public void navigationMediaLink() { - CommonURIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). + final URIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). appendNavigationSegment("Product").appendKeySegment(-7).appendLinksSegment("Photos"); - ODataEntitySetRequest req = client.getRetrieveRequestFactory(). + final ODataEntitySetRequest req = client.getRetrieveRequestFactory(). getEntitySetRequest(uriBuilder.build()); req.setAccept("application/json"); - ODataRetrieveResponse res = req.execute(); + final ODataRetrieveResponse res = req.execute(); assertEquals(200, res.getStatusCode()); - CommonODataEntitySet entitySet = res.getBody(); + final ODataEntitySet entitySet = res.getBody(); assertNotNull(entitySet); - List entity = entitySet.getEntities(); + final List entity = entitySet.getEntities(); assertNotNull(entity); assertEquals(entity.size(), 2); assertEquals(testStaticServiceRootURL + "/ProductPhoto(PhotoId=-3,ProductId=-3)", @@ -234,17 +234,17 @@ public class PropertyRetrieveTestITCase extends AbstractTestITCase { @Test public void navigationMediaLinkInvalidQuery() { - CommonURIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). + final URIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). appendNavigationSegment("Product").appendKeySegment(-7).appendLinksSegment("Photo"); - ODataEntitySetRequest req = client.getRetrieveRequestFactory(). + final ODataEntitySetRequest req = client.getRetrieveRequestFactory(). getEntitySetRequest(uriBuilder.build()); req.setAccept("application/json"); try { - ODataRetrieveResponse res = req.execute(); + final ODataRetrieveResponse res = req.execute(); assertEquals(200, res.getStatusCode()); - CommonODataEntitySet entitySet = res.getBody(); + ODataEntitySet entitySet = res.getBody(); assertNotNull(entitySet); - List entity = entitySet.getEntities(); + final List entity = entitySet.getEntities(); assertNotNull(entity); assertEquals(entity.size(), 2); assertEquals(testStaticServiceRootURL + "/ProductPhoto(PhotoId=-3,ProductId=-3)", entity.get(0). @@ -258,17 +258,17 @@ public class PropertyRetrieveTestITCase extends AbstractTestITCase { @Test public void navigationMediaLinkInvalidFormat() { - CommonURIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). + final URIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). appendNavigationSegment("Product").appendKeySegment(-7).appendLinksSegment("Photos"); - ODataEntitySetRequest req = client.getRetrieveRequestFactory(). + final ODataEntitySetRequest req = client.getRetrieveRequestFactory(). getEntitySetRequest(uriBuilder.build()); req.setAccept("application/atom+xml"); try { - ODataRetrieveResponse res = req.execute(); + final ODataRetrieveResponse res = req.execute(); assertEquals(200, res.getStatusCode()); - ODataEntitySet entitySet = res.getBody(); + final ODataEntitySet entitySet = res.getBody(); assertNotNull(entitySet); - List entity = entitySet.getEntities(); + final List entity = entitySet.getEntities(); assertNotNull(entity); assertEquals(entity.size(), 2); assertEquals(testStaticServiceRootURL + "/ProductPhoto(PhotoId=-3,ProductId=-3)", entity.get(0). diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/PrimitiveValueTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/PrimitiveValueTest.java index 24c13da45..260f9a4ae 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/PrimitiveValueTest.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/v3/PrimitiveValueTest.java @@ -152,9 +152,13 @@ public class PrimitiveValueTest extends AbstractTest { assertEquals(expected.get(Calendar.MILLISECOND), asCalendar.get(Calendar.MILLISECOND)); final Timestamp asTimestamp = value.asPrimitive().toCastValue(Timestamp.class); - assertEquals(expected.get(Calendar.MILLISECOND), asTimestamp.getNanos()); - + assertEquals(expected.get(Calendar.MILLISECOND), asTimestamp.getNanos() / 1000000); + assertEquals("2013-01-10T02:00:00.022Z", value.asPrimitive().toString()); + + final ODataValue parsed = getClient().getObjectFactory().newPrimitiveValueBuilder(). + setType(EdmPrimitiveTypeKind.DateTimeOffset).setText(value.asPrimitive().toString()).build(); + assertEquals("2013-01-10T03:00:00.022+01:00", parsed.asPrimitive().toString()); } @Test diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffset.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffset.java index c2b88c086..2e7ab9853 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffset.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffset.java @@ -19,6 +19,7 @@ package org.apache.olingo.commons.core.edm.primitivetype; import java.sql.Timestamp; +import java.text.DecimalFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; @@ -32,6 +33,13 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; */ public final class EdmDateTimeOffset extends SingletonPrimitiveType { + public static final ThreadLocal NANO_FORMAT = new ThreadLocal() { + @Override + protected DecimalFormat initialValue() { + return new DecimalFormat("000000000"); + } + }; + private static final Pattern PATTERN = Pattern.compile( "(-?\\p{Digit}{4,})-(\\p{Digit}{2})-(\\p{Digit}{2})" + "T(\\p{Digit}{2}):(\\p{Digit}{2})(?::(\\p{Digit}{2})(\\.(\\p{Digit}{0,12}?)0*)?)?" @@ -95,7 +103,9 @@ public final class EdmDateTimeOffset extends SingletonPrimitiveType { dateTimeValue.set(Calendar.MILLISECOND, Short.parseShort(milliSeconds)); if (!decimals.isEmpty()) { - timestamp.setNanos(Integer.parseInt(decimals)); + final int fractionalSecs = Integer.parseInt(decimals); + // if fractional are just milliseconds, convert to nanoseconds + timestamp.setNanos(fractionalSecs < 1000 ? fractionalSecs * 1000000 : fractionalSecs); } } @@ -253,8 +263,13 @@ public final class EdmDateTimeOffset extends SingletonPrimitiveType { */ protected static void appendMilliseconds(final StringBuilder result, final int milliseconds, final Integer precision) throws IllegalArgumentException { + final int digits = milliseconds % 1000 == 0 ? 0 : milliseconds % 100 == 0 ? 1 : milliseconds % 10 == 0 ? 2 : 3; if (digits > 0) { + if (precision == null || precision < digits) { + throw new IllegalArgumentException(); + } + result.append('.'); for (int d = 100; d > 0; d /= 10) { final byte digit = (byte) (milliseconds % (d * 10) / d); @@ -262,10 +277,6 @@ public final class EdmDateTimeOffset extends SingletonPrimitiveType { result.append((char) ('0' + digit)); } } - - if (precision == null || precision < digits) { - throw new IllegalArgumentException(); - } } } @@ -285,7 +296,12 @@ public final class EdmDateTimeOffset extends SingletonPrimitiveType { throw new IllegalArgumentException(); } - result.append('.').append(fractionalSeconds); + String fractionals = NANO_FORMAT.get().format(fractionalSeconds); + // Keep output similar to Calendar's, if possible + if ("000000".equals(fractionals.substring(3))) { + fractionals = fractionals.substring(0, 3); + } + result.append('.').append(fractionals); } } }