diff --git a/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java b/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java index 4f9d970df..08373f626 100644 --- a/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java +++ b/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java @@ -20,19 +20,6 @@ package org.apache.olingo.fit; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import org.apache.olingo.commons.api.data.Feed; -import org.apache.olingo.commons.api.data.Link; -import org.apache.olingo.commons.api.data.Property; -import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; -import org.apache.olingo.commons.core.data.AtomFeedImpl; -import org.apache.olingo.commons.core.data.LinkImpl; -import org.apache.olingo.fit.metadata.Metadata; -import org.apache.olingo.fit.serializer.JsonFeedContainer; -import org.apache.olingo.fit.serializer.JsonEntryContainer; -import org.apache.olingo.fit.utils.ConstantKey; -import org.apache.olingo.fit.utils.Constants; -import org.apache.olingo.fit.utils.DataBinder; - import com.fasterxml.jackson.databind.ObjectMapper; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -83,6 +70,12 @@ import org.apache.olingo.commons.api.data.Container; import org.apache.olingo.commons.api.data.Entry; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.commons.api.data.Feed; +import org.apache.olingo.commons.api.data.Link; +import org.apache.olingo.commons.api.data.Property; +import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; +import org.apache.olingo.commons.core.data.AtomFeedImpl; +import org.apache.olingo.commons.core.data.LinkImpl; import org.apache.olingo.commons.core.data.AtomEntryImpl; import org.apache.olingo.commons.core.data.AtomPropertyImpl; import org.apache.olingo.commons.core.data.AtomSerializer; @@ -98,12 +91,17 @@ import org.apache.olingo.fit.methods.PATCH; import org.apache.olingo.fit.serializer.FITAtomDeserializer; import org.apache.olingo.fit.utils.Accept; import org.apache.olingo.fit.utils.FSManager; - import org.apache.olingo.fit.utils.Commons; import org.apache.olingo.fit.utils.AbstractJSONUtilities; import org.apache.olingo.fit.utils.AbstractUtilities; import org.apache.olingo.fit.utils.AbstractXMLUtilities; import org.apache.olingo.fit.utils.LinkInfo; +import org.apache.olingo.fit.metadata.Metadata; +import org.apache.olingo.fit.serializer.JsonFeedContainer; +import org.apache.olingo.fit.serializer.JsonEntryContainer; +import org.apache.olingo.fit.utils.ConstantKey; +import org.apache.olingo.fit.utils.Constants; +import org.apache.olingo.fit.utils.DataBinder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -114,9 +112,9 @@ public abstract class AbstractServices { */ protected static final Logger LOG = LoggerFactory.getLogger(AbstractServices.class); - private Pattern requestPatter = Pattern.compile("(.*) (http://.*) HTTP/.*"); + private static final Pattern REQUEST_PATTERN = Pattern.compile("(.*) (http://.*) HTTP/.*"); - private static final String boundary = "batch_243234_25424_ef_892u748"; + private static final String BOUNDARY = "batch_243234_25424_ef_892u748"; protected final ODataServiceVersion version; @@ -193,10 +191,10 @@ public abstract class AbstractServices { @POST @Path("/$batch") @Consumes("multipart/mixed") - @Produces("application/octet-stream; boundary=" + boundary) + @Produces("application/octet-stream; boundary=" + BOUNDARY) public Response batch(final @Multipart MultipartBody attachment) { try { - return xml.createBatchResponse(exploreMultipart(attachment.getAllAttachments(), boundary), boundary); + return xml.createBatchResponse(exploreMultipart(attachment.getAllAttachments(), BOUNDARY), BOUNDARY); } catch (IOException e) { return xml.createFaultResponse(Accept.XML.toString(version), e); } @@ -209,7 +207,7 @@ public abstract class AbstractServices { Header header = en.nextElement(); final String request = header.getName() + ":" + header.getValue(); - final Matcher matcher = requestPatter.matcher(request); + final Matcher matcher = REQUEST_PATTERN.matcher(request); if (matcher.find()) { final MultivaluedMap headers = new MultivaluedHashMap(); @@ -343,7 +341,7 @@ public abstract class AbstractServices { bos.write(Constants.CRLF); for (Map.Entry> header : response.getHeaders().entrySet()) { - StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(); for (Object value : header.getValue()) { if (builder.length() > 0) { builder.append(", "); @@ -593,7 +591,7 @@ public abstract class AbstractServices { } else { final Container jcontainer = mapper.readValue(IOUtils.toInputStream(entity), new TypeReference() { - }); + }); entry = (new DataBinder(version)). getAtomEntry(jcontainer.getObject()); @@ -666,13 +664,13 @@ public abstract class AbstractServices { replaceAll("\"Salary\":[0-9]*,", "\"Salary\":0,"). replaceAll("\"Title\":\".*\"", "\"Title\":\"[Sacked]\""). replaceAll("\\.*\\", - "0"). + "0"). replaceAll("\\.*\\", "[Sacked]"); final FSManager fsManager = FSManager.instance(version); fsManager.putInMemory(IOUtils.toInputStream(newContent, "UTF-8"), fsManager.getAbsolutePath(Commons.getEntityBasePath("Person", entityId) + Constants.get(version, - ConstantKey.ENTITY), utils.getKey())); + ConstantKey.ENTITY), utils.getKey())); return utils.getValue().createResponse(null, null, utils.getKey(), Response.Status.NO_CONTENT); } catch (Exception e) { @@ -724,9 +722,9 @@ public abstract class AbstractServices { final Long newSalary = Long.valueOf(salaryMatcher.group(1)) + n; newContent = newContent. replaceAll("\"Salary\":" + salaryMatcher.group(1) + ",", - "\"Salary\":" + newSalary + ","). + "\"Salary\":" + newSalary + ","). replaceAll("\\" + salaryMatcher.group(1) + "", - "" + newSalary + ""); + "" + newSalary + ""); } FSManager.instance(version).putInMemory(IOUtils.toInputStream(newContent, "UTF-8"), @@ -858,7 +856,7 @@ public abstract class AbstractServices { mapper.writeValue( writer, new JsonFeedContainer(container.getContextURL(), container.getMetadataETag(), - new DataBinder(version).getJsonFeed(container.getObject()))); + new DataBinder(version).getJsonFeed(container.getObject()))); } return xml.createResponse(new ByteArrayInputStream(content.toByteArray()), @@ -1040,7 +1038,7 @@ public abstract class AbstractServices { final ObjectMapper mapper = Commons.getJsonMapper(version); mapper.writeValue( writer, new JsonEntryContainer(container.getContextURL(), container.getMetadataETag(), - (new DataBinder(version)).getJsonEntry((AtomEntryImpl) container.getObject()))); + (new DataBinder(version)).getJsonEntry((AtomEntryImpl) container.getObject()))); } return xml.createResponse(new ByteArrayInputStream(content.toByteArray()), @@ -1469,27 +1467,50 @@ public abstract class AbstractServices { private Response navigateEntity( final Accept acceptType, - String entitySetName, - String entityId, - String path) throws Exception { - final String basePath = Commons.getEntityBasePath(entitySetName, entityId); - - final LinkInfo linkInfo = xml.readLinks(entitySetName, entityId, path, Accept.XML); - final Map.Entry> links = xml.extractLinkURIs(linkInfo.getLinks()); + final String entitySetName, + final String entityId, + final String path) throws Exception { + final LinkInfo linkInfo; InputStream stream; + if (version.compareTo(ODataServiceVersion.V30) <= 0) { + linkInfo = xml.readLinks(entitySetName, entityId, path, Accept.XML); + final Map.Entry> links = xml.extractLinkURIs(linkInfo.getLinks()); - switch (acceptType) { - case JSON: - case JSON_FULLMETA: - case JSON_NOMETA: - stream = json.readEntities(links.getValue(), path, links.getKey(), linkInfo.isFeed()); - stream = json.wrapJsonEntities(stream); - break; - default: - stream = xml.readEntities(links.getValue(), path, links.getKey(), linkInfo.isFeed()); + switch (acceptType) { + case JSON: + case JSON_FULLMETA: + case JSON_NOMETA: + stream = json.readEntities(links.getValue(), path, links.getKey(), linkInfo.isFeed()); + stream = json.wrapJsonEntities(stream); + break; + default: + stream = xml.readEntities(links.getValue(), path, links.getKey(), linkInfo.isFeed()); + } + + } else { + linkInfo = xml.readLinks(entitySetName, entityId, path, Accept.ATOM); + if (acceptType == Accept.ATOM) { + stream = linkInfo.getLinks(); + } else { + final FITAtomDeserializer atomDeserializer = Commons.getAtomDeserializer(version); + final DataBinder dataBinder = new DataBinder(version); + final ObjectMapper mapper = Commons.getJsonMapper(version); + + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final Object object; + if (linkInfo.isFeed()) { + final Container container = atomDeserializer.read(linkInfo.getLinks(), AtomFeedImpl.class); + object = dataBinder.getJsonFeed(container.getObject()); + } else { + final Container container = atomDeserializer.read(linkInfo.getLinks(), AtomEntryImpl.class); + object = dataBinder.getJsonEntry(container.getObject()); + } + mapper.writeValue(baos, object); + stream = new ByteArrayInputStream(baos.toByteArray()); + } } - + final String basePath = Commons.getEntityBasePath(entitySetName, entityId); return xml.createResponse(stream, Commons.getETag(basePath, version), acceptType); } diff --git a/fit/src/main/java/org/apache/olingo/fit/V4Services.java b/fit/src/main/java/org/apache/olingo/fit/V4Services.java index 651ae8518..875bee868 100644 --- a/fit/src/main/java/org/apache/olingo/fit/V4Services.java +++ b/fit/src/main/java/org/apache/olingo/fit/V4Services.java @@ -223,7 +223,7 @@ public class V4Services extends AbstractServices { final ObjectMapper mapper = Commons.getJsonMapper(version); final DataBinder dataBinder = new DataBinder(version); - Container jsonContainer = mapper.readValue(IOUtils.toInputStream(changes), + final Container jsonContainer = mapper.readValue(IOUtils.toInputStream(changes), new TypeReference() { }); jsonContainer.getObject().setType(typeInfo.getFullQualifiedName().toString()); @@ -243,7 +243,6 @@ public class V4Services extends AbstractServices { return xml.createResponse(null, null, acceptType, Response.Status.NO_CONTENT); } catch (Exception e) { - e.printStackTrace(); return xml.createFaultResponse(accept, e); } } diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/AbstractJSONUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/AbstractJSONUtilities.java index 1354a6f1c..c754b00ff 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/AbstractJSONUtilities.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/AbstractJSONUtilities.java @@ -359,7 +359,7 @@ public abstract class AbstractJSONUtilities extends AbstractUtilities { node.set(Constants.get(version, ConstantKey.JSON_NEXTLINK_NAME), new TextNode(next)); } - return IOUtils.toInputStream(node.toString(), "UTf-8"); + return IOUtils.toInputStream(node.toString(), "UTF-8"); } @Override diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/AbstractUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/AbstractUtilities.java index 8ef447259..4a2af9345 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/AbstractUtilities.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/AbstractUtilities.java @@ -365,7 +365,7 @@ public abstract class AbstractUtilities { fsManager.putInMemory( IOUtils.toInputStream(entity), fsManager.getAbsolutePath(path + Constants.get(version, ConstantKey.ENTITY), - Accept.JSON_FULLMETA)); + Accept.JSON_FULLMETA)); // ----------------------------------------- return readEntity(entitySetName, entityKey, getDefaultFormat()).getValue(); @@ -415,7 +415,6 @@ public abstract class AbstractUtilities { } public Response createBatchResponse(final InputStream stream, final String boundary) { - final Response.ResponseBuilder builder = Response.accepted(stream); builder.header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version.toString() + ";"); return builder.build(); @@ -423,6 +422,7 @@ public abstract class AbstractUtilities { public Response createResponse( final InputStream entity, final String etag, final Accept accept, final Response.Status status) { + final Response.ResponseBuilder builder = Response.ok(); if (version.compareTo(ODataServiceVersion.V30) <= 0) { builder.header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version.toString() + ";"); @@ -444,8 +444,8 @@ public abstract class AbstractUtilities { try { final InputStream toBeStreamedBack; - if (accept != null && (Accept.JSON == accept || Accept.JSON_NOMETA == accept)) { - toBeStreamedBack = Commons.changeFormat(entity, accept); + if (Accept.JSON == accept || Accept.JSON_NOMETA == accept) { + toBeStreamedBack = Commons.changeFormat(entity, version, accept); } else { toBeStreamedBack = entity; } @@ -685,10 +685,10 @@ public abstract class AbstractUtilities { } public String getLinksBasePath(final String entitySetName, final String entityId) { - return entitySetName + File.separatorChar + Commons.getEntityKey(entityId) + File.separatorChar - + Constants.get(version, ConstantKey.LINKS_FILE_PATH) + File.separatorChar; + return entitySetName + File.separatorChar + Commons.getEntityKey(entityId) + File.separatorChar + + Constants.get(version, ConstantKey.LINKS_FILE_PATH) + File.separatorChar; } - + /** * Retrieves entity links about the given link name. * diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/Commons.java b/fit/src/main/java/org/apache/olingo/fit/utils/Commons.java index 70100a247..beeb81ca9 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/Commons.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/Commons.java @@ -251,7 +251,7 @@ public abstract class Commons { return IOUtils.toInputStream(links.toString(), "UTf-8"); } - public static InputStream changeFormat(final InputStream is, final Accept target) { + public static InputStream changeFormat(final InputStream is, final ODataServiceVersion version, final Accept target) { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { @@ -260,7 +260,7 @@ public abstract class Commons { final ObjectMapper mapper = new ObjectMapper(); final JsonNode node = - changeFormat((ObjectNode) mapper.readTree(new ByteArrayInputStream(bos.toByteArray())), target); + changeFormat((ObjectNode) mapper.readTree(new ByteArrayInputStream(bos.toByteArray())), version, target); return IOUtils.toInputStream(node.toString(), "UTF-8"); } catch (Exception e) { @@ -272,30 +272,35 @@ public abstract class Commons { } @SuppressWarnings("fallthrough") - public static JsonNode changeFormat(final ObjectNode node, final Accept target) { + public static JsonNode changeFormat(final ObjectNode node, final ODataServiceVersion version, final Accept target) { final List toBeRemoved = new ArrayList(); - final Map toBeReplaced = new HashMap(); - switch (target) { case JSON_NOMETA: // nometa + minimal - toBeRemoved.add(Constants.get(ConstantKey.JSON_ODATAMETADATA_NAME)); + toBeRemoved.add(Constants.get(version, ConstantKey.JSON_ODATAMETADATA_NAME)); case JSON: // minimal - toBeRemoved.add(Constants.get(ConstantKey.JSON_EDITLINK_NAME)); - toBeRemoved.add(Constants.get(ConstantKey.JSON_ID_NAME)); - toBeRemoved.add(Constants.get(ConstantKey.JSON_TYPE_NAME)); + toBeRemoved.add(Constants.get(version, ConstantKey.JSON_EDITLINK_NAME)); + toBeRemoved.add(Constants.get(version, ConstantKey.JSON_ID_NAME)); + toBeRemoved.add(Constants.get(version, ConstantKey.JSON_TYPE_NAME)); final Iterator> fields = node.fields(); while (fields.hasNext()) { final Map.Entry field = fields.next(); - if (field.getKey().endsWith(Constants.get(ConstantKey.JSON_MEDIA_SUFFIX)) - || field.getKey().endsWith(Constants.get(ConstantKey.JSON_NAVIGATION_SUFFIX)) - || field.getKey().endsWith(Constants.get(ConstantKey.JSON_TYPE_SUFFIX))) { + if (field.getKey().endsWith(Constants.get(version, ConstantKey.JSON_MEDIA_SUFFIX)) + || field.getKey().endsWith(Constants.get(version, ConstantKey.JSON_NAVIGATION_SUFFIX)) + || field.getKey().endsWith(Constants.get(version, ConstantKey.JSON_TYPE_SUFFIX))) { toBeRemoved.add(field.getKey()); } else if (field.getValue().isObject()) { - toBeReplaced.put(field.getKey(), changeFormat((ObjectNode) field.getValue(), target)); + changeFormat((ObjectNode) field.getValue(), version, target); + } else if (field.getValue().isArray()) { + for (final Iterator subItor = field.getValue().elements(); subItor.hasNext();) { + final JsonNode subNode = subItor.next(); + if (subNode.isObject()) { + changeFormat((ObjectNode) subNode, version, target); + } + } } } case JSON_FULLMETA: @@ -305,14 +310,7 @@ public abstract class Commons { default: throw new UnsupportedOperationException(target.name()); } - - for (String field : toBeRemoved) { - node.remove(field); - } - - for (Map.Entry field : toBeReplaced.entrySet()) { - node.replace(field.getKey(), field.getValue()); - } + node.remove(toBeRemoved); return node; } diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/Constants.java b/fit/src/main/java/org/apache/olingo/fit/utils/Constants.java index 975a537e8..0b5cf66cf 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/Constants.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/Constants.java @@ -41,6 +41,8 @@ public class Constants { // ----------------------------- // V4 only // ----------------------------- + v4constants.put(ConstantKey.JSON_ID_NAME, "@odata.id"); + v4constants.put(ConstantKey.JSON_TYPE_NAME, "@odata.type"); v4constants.put(ConstantKey.JSON_NAVIGATION_SUFFIX, "@odata.navigationLink"); v4constants.put(ConstantKey.DATASERVICES_NS, "http://docs.oasis-open.org/odata/ns/dataservices"); v4constants.put(ConstantKey.METADATA_NS, "http://docs.oasis-open.org/odata/ns/metadata"); diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/DataBinder.java b/fit/src/main/java/org/apache/olingo/fit/utils/DataBinder.java index b984c3229..f7c0826eb 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/DataBinder.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/DataBinder.java @@ -203,20 +203,20 @@ public class DataBinder { public JSONPropertyImpl getJsonProperty(final AtomPropertyImpl atomproperty) { final JSONPropertyImpl jsonproperty = new JSONPropertyImpl(); BeanUtils.copyProperties(atomproperty, jsonproperty, "value"); - - if (atomproperty.getValue() instanceof ComplexValueImpl) { + + if (atomproperty.getValue().isComplex()) { final ComplexValueImpl complex = new ComplexValueImpl(); jsonproperty.setValue(complex); for (Property field : atomproperty.getValue().asComplex().get()) { complex.get().add(getJsonProperty((AtomPropertyImpl) field)); } - } else if (atomproperty.getValue() instanceof CollectionValueImpl) { + } else if (atomproperty.getValue().isCollection()) { final CollectionValueImpl collection = new CollectionValueImpl(); jsonproperty.setValue(collection); for (Value element : atomproperty.getValue().asCollection().get()) { - if (element instanceof ComplexValueImpl) { + if (element.isComplex()) { final ComplexValueImpl complex = new ComplexValueImpl(); collection.get().add(complex); diff --git a/fit/src/main/resources/V40/Accounts/101/links/MyPaymentInstruments(101901).xml b/fit/src/main/resources/V40/Accounts/101/links/MyPaymentInstruments(101901).xml index f1002bac0..8a9d14bb8 100644 --- a/fit/src/main/resources/V40/Accounts/101/links/MyPaymentInstruments(101901).xml +++ b/fit/src/main/resources/V40/Accounts/101/links/MyPaymentInstruments(101901).xml @@ -21,9 +21,9 @@ --> - - - + + + <updated>2014-04-14T12:47:37Z</updated> diff --git a/fit/src/main/resources/V40/Accounts/101/links/MyPaymentInstruments.xml b/fit/src/main/resources/V40/Accounts/101/links/MyPaymentInstruments.xml index 5593a7a0b..e8b1febd5 100644 --- a/fit/src/main/resources/V40/Accounts/101/links/MyPaymentInstruments.xml +++ b/fit/src/main/resources/V40/Accounts/101/links/MyPaymentInstruments.xml @@ -25,9 +25,9 @@ <updated>2014-04-14T12:45:33Z</updated> <entry> <category term="#Microsoft.Test.OData.Services.ODataWCFService.PaymentInstrument" scheme="http://docs.oasis-open.org/odata/ns/scheme"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="potato"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="potato"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="potato"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101901)/TheStoredPI"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101901)/BillingStatements"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101901)/BackupStoredPI"/> <id/> <title/> <updated>2014-04-14T12:45:33Z</updated> @@ -44,10 +44,10 @@ </entry> <entry> <category term="#Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI" scheme="http://docs.oasis-open.org/odata/ns/scheme"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="potato"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="potato"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="potato"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/CreditRecords" type="application/atom+xml;type=feed" title="CreditRecords" href="potato"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101902)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/TheStoredPI"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101902)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/BillingStatements"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101902)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/BackupStoredPI"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/CreditRecords" type="application/atom+xml;type=feed" title="CreditRecords" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101902)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/CreditRecords"/> <id/> <title/> <updated>2014-04-14T12:45:33Z</updated> @@ -69,10 +69,10 @@ </entry> <entry> <category term="#Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI" scheme="http://docs.oasis-open.org/odata/ns/scheme"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="potato"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="potato"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="potato"/> - <link rel="http://docs.oasis-open.org/odata/ns/related/CreditRecords" type="application/atom+xml;type=feed" title="CreditRecords" href="potato"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101903)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/TheStoredPI"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101903)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/BillingStatements"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101903)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/BackupStoredPI"/> + <link rel="http://docs.oasis-open.org/odata/ns/related/CreditRecords" type="application/atom+xml;type=feed" title="CreditRecords" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101903)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/CreditRecords"/> <id/> <title/> <updated>2014-04-14T12:45:33Z</updated> diff --git a/lib/client-core/pom.xml b/lib/client-core/pom.xml index 0d09e757b..e8c20b586 100644 --- a/lib/client-core/pom.xml +++ b/lib/client-core/pom.xml @@ -58,6 +58,10 @@ <groupId>xmlunit</groupId> <artifactId>xmlunit</artifactId> </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + </dependency> <dependency> <groupId>org.apache.olingo</groupId> @@ -70,10 +74,27 @@ <build> <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <inherited>true</inherited> + <configuration> + <systemPropertyVariables> + <propertyName>org.slf4j.simpleLogger.defaultLogLevel</propertyName> + <org.slf4j.simpleLogger.defaultLogLevel>ERROR</org.slf4j.simpleLogger.defaultLogLevel> + </systemPropertyVariables> + </configuration> + </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <inherited>true</inherited> + <configuration> + <systemPropertyVariables> + <propertyName>org.slf4j.simpleLogger.defaultLogLevel</propertyName> + <org.slf4j.simpleLogger.defaultLogLevel>DEBUG</org.slf4j.simpleLogger.defaultLogLevel> + </systemPropertyVariables> + </configuration> </plugin> <plugin> diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/AbstractBaseTestITCase.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/AbstractBaseTestITCase.java new file mode 100644 index 000000000..fc1e91d4f --- /dev/null +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/AbstractBaseTestITCase.java @@ -0,0 +1,98 @@ +/* + * 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.client.core.it; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import org.apache.commons.io.IOUtils; +import org.apache.olingo.client.api.CommonODataClient; +import org.apache.olingo.commons.api.data.Entry; +import org.apache.olingo.commons.api.data.Feed; +import org.apache.olingo.commons.api.domain.CommonODataEntity; +import org.apache.olingo.commons.api.domain.CommonODataProperty; +import org.apache.olingo.commons.api.domain.ODataValue; +import org.apache.olingo.commons.core.data.AtomEntryImpl; +import org.apache.olingo.commons.core.data.JSONEntryImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractBaseTestITCase { + + /** + * Logger. + */ + protected static final Logger LOG = LoggerFactory.getLogger(AbstractBaseTestITCase.class); + + @SuppressWarnings("rawtypes") + protected abstract CommonODataClient getClient(); + + protected void debugEntry(final Entry entry, final String message) { + if (LOG.isDebugEnabled()) { + final StringWriter writer = new StringWriter(); + getClient().getSerializer().entry(entry, writer); + writer.flush(); + LOG.debug(message + "\n{}", writer.toString()); + } + } + + protected void debugFeed(final Feed feed, final String message) { + if (LOG.isDebugEnabled()) { + final StringWriter writer = new StringWriter(); + getClient().getSerializer().feed(feed, writer); + writer.flush(); + LOG.debug(message + "\n{}", writer.toString()); + } + } + + protected void debugODataProperty(final CommonODataProperty property, final String message) { + LOG.debug(message + "\n{}", property.toString()); + } + + protected void debugODataValue(final ODataValue value, final String message) { + LOG.debug(message + "\n{}", value.toString()); + } + + protected void debugODataEntity(final CommonODataEntity entity, final String message) { + if (LOG.isDebugEnabled()) { + StringWriter writer = new StringWriter(); + getClient().getSerializer().entry(getClient().getBinder().getEntry(entity, AtomEntryImpl.class), writer); + writer.flush(); + LOG.debug(message + " (Atom)\n{}", writer.toString()); + + writer = new StringWriter(); + getClient().getSerializer().entry(getClient().getBinder().getEntry(entity, JSONEntryImpl.class), writer); + writer.flush(); + LOG.debug(message + " (JSON)\n{}", writer.toString()); + } + } + + protected void debugInputStream(final InputStream input, final String message) { + if (LOG.isDebugEnabled()) { + try { + LOG.debug(message + "\n{}", IOUtils.toString(input)); + } catch (IOException e) { + LOG.error("Error writing stream", e); + } finally { + IOUtils.closeQuietly(input); + } + } + } + +} diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/AbstractMetadataTestITCase.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/AbstractMetadataTestITCase.java index 4f6542119..623eca8e8 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/AbstractMetadataTestITCase.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/AbstractMetadataTestITCase.java @@ -22,6 +22,7 @@ import org.apache.olingo.client.api.CommonODataClient; public abstract class AbstractMetadataTestITCase { + @SuppressWarnings("rawtypes") protected abstract CommonODataClient getClient(); protected String getTestServiceRoot() { diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/AbstractTestITCase.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/AbstractTestITCase.java index 90f0510e8..f9405ec11 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/AbstractTestITCase.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v3/AbstractTestITCase.java @@ -26,8 +26,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; import java.net.URI; import java.util.ArrayList; import java.util.Collection; @@ -36,7 +34,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.olingo.client.api.communication.ODataClientErrorException; import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest; @@ -52,9 +49,8 @@ import org.apache.olingo.client.api.http.HttpMethod; import org.apache.olingo.client.api.uri.CommonURIBuilder; import org.apache.olingo.client.api.v3.ODataClient; import org.apache.olingo.client.core.ODataClientFactory; +import org.apache.olingo.client.core.it.AbstractBaseTestITCase; import org.apache.olingo.client.core.uri.URIUtils; -import org.apache.olingo.commons.api.data.Entry; -import org.apache.olingo.commons.api.data.Feed; import org.apache.olingo.commons.api.domain.CommonODataEntity; import org.apache.olingo.commons.api.domain.CommonODataEntitySet; import org.apache.olingo.commons.api.domain.CommonODataProperty; @@ -68,19 +64,9 @@ import org.apache.olingo.commons.api.domain.v3.ODataEntity; import org.apache.olingo.commons.api.domain.v3.ODataProperty; import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.format.ODataPubFormat; -import org.apache.olingo.commons.core.data.AtomEntryImpl; -import org.apache.olingo.commons.core.data.JSONEntryImpl; - import org.junit.BeforeClass; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -public abstract class AbstractTestITCase { - - /** - * Logger. - */ - protected static final Logger LOG = LoggerFactory.getLogger(AbstractTestITCase.class); +public abstract class AbstractTestITCase extends AbstractBaseTestITCase { protected static final FullQualifiedName TEST_PRODUCT_TYPE = new FullQualifiedName("Microsoft.Test.OData.Services.AstoriaDefaultService.Product"); @@ -114,6 +100,7 @@ public abstract class AbstractTestITCase { client = ODataClientFactory.getV3(); } + @Override protected ODataClient getClient() { return client; } @@ -307,58 +294,6 @@ public abstract class AbstractTestITCase { return entity; } - protected void debugEntry(final Entry entry, final String message) { - if (LOG.isDebugEnabled()) { - final StringWriter writer = new StringWriter(); - getClient().getSerializer().entry(entry, writer); - writer.flush(); - LOG.debug(message + "\n{}", writer.toString()); - } - } - - protected void debugFeed(final Feed feed, final String message) { - if (LOG.isDebugEnabled()) { - final StringWriter writer = new StringWriter(); - getClient().getSerializer().feed(feed, writer); - writer.flush(); - LOG.debug(message + "\n{}", writer.toString()); - } - } - - protected void debugODataProperty(final ODataProperty property, final String message) { - LOG.debug(message + "\n{}", property.toString()); - } - - protected void debugODataValue(final ODataValue value, final String message) { - LOG.debug(message + "\n{}", value.toString()); - } - - protected void debugODataEntity(final ODataEntity entity, final String message) { - if (LOG.isDebugEnabled()) { - StringWriter writer = new StringWriter(); - getClient().getSerializer().entry(getClient().getBinder().getEntry(entity, AtomEntryImpl.class), writer); - writer.flush(); - LOG.debug(message + " (Atom)\n{}", writer.toString()); - - writer = new StringWriter(); - getClient().getSerializer().entry(getClient().getBinder().getEntry(entity, JSONEntryImpl.class), writer); - writer.flush(); - LOG.debug(message + " (JSON)\n{}", writer.toString()); - } - } - - protected void debugInputStream(final InputStream input, final String message) { - if (LOG.isDebugEnabled()) { - try { - LOG.debug(message + "\n{}", IOUtils.toString(input)); - } catch (IOException e) { - LOG.error("Error writing stream", e); - } finally { - IOUtils.closeQuietly(input); - } - } - } - protected String getETag(final URI uri) { final ODataRetrieveResponse<ODataEntity> res = getClient().getRetrieveRequestFactory(). getEntityRequest(uri).execute(); diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/AbstractTestITCase.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/AbstractTestITCase.java index 8bdcdb9c3..05a195c82 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/AbstractTestITCase.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/AbstractTestITCase.java @@ -27,15 +27,12 @@ import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRe import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; import org.apache.olingo.client.api.v4.ODataClient; import org.apache.olingo.client.core.ODataClientFactory; +import org.apache.olingo.client.core.it.AbstractBaseTestITCase; import org.apache.olingo.commons.api.domain.v4.ODataEntity; import org.apache.olingo.commons.api.format.ODataPubFormat; import org.junit.BeforeClass; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -public abstract class AbstractTestITCase { - - protected static final Logger LOG = LoggerFactory.getLogger(AbstractTestITCase.class); +public abstract class AbstractTestITCase extends AbstractBaseTestITCase { protected static ODataClient client; @@ -60,6 +57,7 @@ public abstract class AbstractTestITCase { client = ODataClientFactory.getV4(); } + @Override protected ODataClient getClient() { return client; } diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/EntityCreateTestITCase.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/EntityCreateTestITCase.java index 3de27e8a6..9385daab0 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/EntityCreateTestITCase.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/EntityCreateTestITCase.java @@ -21,20 +21,51 @@ package org.apache.olingo.client.core.it.v4; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.URI; +import java.util.Calendar; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomUtils; import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest; +import org.apache.olingo.client.api.communication.response.ODataDeleteResponse; +import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse; import org.apache.olingo.commons.api.domain.ODataCollectionValue; import org.apache.olingo.commons.api.domain.v4.ODataEntity; +import org.apache.olingo.commons.api.domain.v4.ODataEntitySet; import org.apache.olingo.commons.api.domain.v4.ODataProperty; import org.apache.olingo.commons.api.domain.v4.ODataValue; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.format.ODataPubFormat; import org.apache.olingo.commons.core.domain.v4.ODataEntityImpl; +import org.junit.Assume; +import org.junit.BeforeClass; import org.junit.Test; public class EntityCreateTestITCase extends AbstractTestITCase { - private void createOrder(final ODataPubFormat format, final int id) { + private static final String serviceRoot = "http://odatae2etest.azurewebsites.net/javatest/DefaultService"; + + // TODO: remove once fit provides contained entity CRUD + @BeforeClass + public static void checkServerIsOnline() throws IOException { + final Socket socket = new Socket(); + boolean reachable = false; + try { + socket.connect(new InetSocketAddress("odatae2etest.azurewebsites.net", 80), 2000); + reachable = true; + } catch (Exception e) { + LOG.warn("External test service not reachable, ignoring this whole class: {}", + OperationImportInvokeTestITCase.class.getName()); + } finally { + IOUtils.closeQuietly(socket); + } + Assume.assumeTrue(reachable); + } + + private void order(final ODataPubFormat format, final int id) { final ODataEntity order = new ODataEntityImpl( new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService.Order")); @@ -73,11 +104,67 @@ public class EntityCreateTestITCase extends AbstractTestITCase { @Test public void atom() { - createOrder(ODataPubFormat.ATOM, 1000); + order(ODataPubFormat.ATOM, 1000); } @Test public void json() { - createOrder(ODataPubFormat.JSON, 1001); + order(ODataPubFormat.JSON, 1001); + } + + private void onContained(final ODataPubFormat format) { + final URI uri = getClient().getURIBuilder(serviceRoot).appendEntitySetSegment("Accounts").appendKeySegment(101). + appendNavigationSegment("MyPaymentInstruments").build(); + + // 1. read contained collection before any operation + ODataEntitySet instruments = getClient().getRetrieveRequestFactory().getEntitySetRequest(uri).execute().getBody(); + assertNotNull(instruments); + final int sizeBefore = instruments.getCount(); + + // 2. instantiate an ODataEntity of the same type as the collection above + final ODataEntity instrument = getClient().getObjectFactory(). + newEntity(new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService.PaymentInstrument")); + + int id = RandomUtils.nextInt(101999, 105000); + instrument.getProperties().add(getClient().getObjectFactory().newPrimitiveProperty("PaymentInstrumentID", + getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt32(id))); + instrument.getProperties().add(getClient().getObjectFactory().newPrimitiveProperty("FriendlyName", + getClient().getObjectFactory().newPrimitiveValueBuilder().buildString("New one"))); + instrument.getProperties().add(getClient().getObjectFactory().newPrimitiveProperty("CreatedDate", + getClient().getObjectFactory().newPrimitiveValueBuilder(). + setType(EdmPrimitiveTypeKind.DateTimeOffset).setValue(Calendar.getInstance()).build())); + + // 3. create it as contained entity + final ODataEntityCreateRequest<ODataEntity> req = getClient().getCUDRequestFactory(). + getEntityCreateRequest(uri, instrument); + final ODataEntityCreateResponse<ODataEntity> res = req.execute(); + assertEquals(201, res.getStatusCode()); + + // 4. verify that the contained collection effectively grew + instruments = getClient().getRetrieveRequestFactory().getEntitySetRequest(uri).execute().getBody(); + assertNotNull(instruments); + final int sizeAfter = instruments.getCount(); + assertEquals(sizeBefore + 1, sizeAfter); + + // 5. remove the contained entity created above + final ODataDeleteResponse deleteRes = getClient().getCUDRequestFactory(). + getDeleteRequest(getClient().getURIBuilder(uri.toASCIIString()).appendKeySegment(id).build()).execute(); + assertEquals(204, deleteRes.getStatusCode()); + + // 6. verify that the contained collection effectively reduced + instruments = getClient().getRetrieveRequestFactory().getEntitySetRequest(uri).execute().getBody(); + assertNotNull(instruments); + final int sizeEnd = instruments.getCount(); + assertEquals(sizeBefore, sizeEnd); + } + + @Test + public void atomOnContained() { + onContained(ODataPubFormat.ATOM); + } + + @Test + public void jsonOnContained() { + onContained(ODataPubFormat.JSON); } } diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/AtomTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/AtomTest.java index ed6b8c089..fad3624a0 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/AtomTest.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/AtomTest.java @@ -60,6 +60,7 @@ public class AtomTest extends JSONTest { return result.toString(); } + @Override protected void assertSimilar(final String filename, final String actual) throws Exception { final Diff diff = new Diff(cleanup(IOUtils.toString(getClass().getResourceAsStream(filename))), actual); diff.overrideElementQualifier(new AtomLinksQualifier()); diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractJsonSerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractJsonSerializer.java index 6daf2aff0..2fa89d455 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractJsonSerializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractJsonSerializer.java @@ -33,6 +33,7 @@ import org.apache.olingo.commons.api.data.CollectionValue; import org.apache.olingo.commons.api.data.Entry; import org.apache.olingo.commons.api.data.Link; import org.apache.olingo.commons.api.data.Linked; +import org.apache.olingo.commons.api.data.PrimitiveValue; import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.Value; import org.apache.olingo.commons.api.domain.ODataLinkType; @@ -140,6 +141,26 @@ abstract class AbstractJsonSerializer<T> extends ODataJacksonSerializer<T> { jgen.writeEndArray(); } + protected void primitiveValue(final JsonGenerator jgen, final EdmTypeInfo typeInfo, final PrimitiveValue value) + throws IOException { + + final boolean isNumber = typeInfo == null + ? NumberUtils.isNumber(value.get()) + : ArrayUtils.contains(NUMBER_TYPES, typeInfo.getPrimitiveTypeKind()); + final boolean isBoolean = typeInfo == null + ? (value.get().equalsIgnoreCase(Boolean.TRUE.toString()) + || value.get().equalsIgnoreCase(Boolean.FALSE.toString())) + : typeInfo.getPrimitiveTypeKind() == EdmPrimitiveTypeKind.Boolean; + + if (isNumber) { + jgen.writeNumber(value.get()); + } else if (isBoolean) { + jgen.writeBoolean(BooleanUtils.toBoolean(value.get())); + } else { + jgen.writeString(value.get()); + } + } + private void value(final JsonGenerator jgen, final String type, final Value value) throws IOException { final EdmTypeInfo typeInfo = type == null ? null @@ -148,21 +169,7 @@ abstract class AbstractJsonSerializer<T> extends ODataJacksonSerializer<T> { if (value == null || value.isNull()) { jgen.writeNull(); } else if (value.isPrimitive()) { - final boolean isNumber = typeInfo == null - ? NumberUtils.isNumber(value.asPrimitive().get()) - : ArrayUtils.contains(NUMBER_TYPES, typeInfo.getPrimitiveTypeKind()); - final boolean isBoolean = typeInfo == null - ? (value.asPrimitive().get().equalsIgnoreCase(Boolean.TRUE.toString()) - || value.asPrimitive().get().equalsIgnoreCase(Boolean.FALSE.toString())) - : typeInfo.getPrimitiveTypeKind() == EdmPrimitiveTypeKind.Boolean; - - if (isNumber) { - jgen.writeNumber(value.asPrimitive().get()); - } else if (isBoolean) { - jgen.writeBoolean(BooleanUtils.toBoolean(value.asPrimitive().get())); - } else { - jgen.writeString(value.asPrimitive().get()); - } + primitiveValue(jgen, typeInfo, value.asPrimitive()); } else if (value.isEnum()) { jgen.writeString(value.asEnum().get()); } else if (value.isGeospatial()) { diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomDeserializer.java index f9a9c8241..2a15ddc2b 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomDeserializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomDeserializer.java @@ -271,6 +271,10 @@ public class AtomDeserializer extends AbstractAtomDealer { break; case PRIMITIVE: + // No type specified? Defaults to Edm.String + if (typeInfo == null) { + property.setType(EdmPrimitiveTypeKind.String.getFullQualifiedName().toString()); + } value = fromPrimitive(reader, start, typeInfo); break; diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java index 266566d2d..e953948fa 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AtomSerializer.java @@ -34,6 +34,7 @@ import org.apache.olingo.commons.api.data.Feed; import org.apache.olingo.commons.api.data.Link; import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.Value; +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.core.edm.EdmTypeInfo; @@ -102,9 +103,11 @@ public class AtomSerializer extends AbstractAtomDealer { } if (StringUtils.isNotBlank(property.getType())) { - writer.writeAttribute(Constants.PREFIX_METADATA, version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), - Constants.ATTR_TYPE, - new EdmTypeInfo.Builder().setTypeExpression(property.getType()).build().external(version)); + final EdmTypeInfo typeInfo = new EdmTypeInfo.Builder().setTypeExpression(property.getType()).build(); + if (!EdmPrimitiveTypeKind.String.getFullQualifiedName().toString().equals(typeInfo.internal())) { + writer.writeAttribute(Constants.PREFIX_METADATA, version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), + Constants.ATTR_TYPE, typeInfo.external(version)); + } } if (property.getValue().isNull()) { diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntrySerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntrySerializer.java index 3470ab5a9..bdfa4394b 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntrySerializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONEntrySerializer.java @@ -59,15 +59,11 @@ public class JSONEntrySerializer extends AbstractJsonSerializer<JSONEntryImpl> { if (serverMode) { if (version.compareTo(ODataServiceVersion.V40) >= 0 && StringUtils.isNotBlank(container.getMetadataETag())) { - jgen.writeStringField( - Constants.JSON_METADATA_ETAG, - container.getMetadataETag()); + jgen.writeStringField(Constants.JSON_METADATA_ETAG, container.getMetadataETag()); } if (StringUtils.isNotBlank(entry.getETag())) { - jgen.writeStringField( - version.getJSONMap().get(ODataServiceVersion.JSON_ETAG), - entry.getETag()); + jgen.writeStringField(version.getJSONMap().get(ODataServiceVersion.JSON_ETAG), entry.getETag()); } } diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONPropertySerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONPropertySerializer.java index 65fd193e7..1085fa561 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONPropertySerializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONPropertySerializer.java @@ -25,6 +25,7 @@ import java.io.IOException; import org.apache.olingo.commons.api.Constants; import org.apache.olingo.commons.api.data.Container; import org.apache.olingo.commons.api.data.Property; +import org.apache.olingo.commons.core.edm.EdmTypeInfo; /** * Writes out JSON string from <tt>JSONPropertyImpl</tt>. @@ -51,7 +52,12 @@ public class JSONPropertySerializer extends AbstractJsonSerializer<JSONPropertyI if (property.getValue().isNull()) { jgen.writeBooleanField(Constants.JSON_NULL, true); } else if (property.getValue().isPrimitive()) { - jgen.writeStringField(Constants.VALUE, property.getValue().asPrimitive().get()); + final EdmTypeInfo typeInfo = property.getType() == null + ? null + : new EdmTypeInfo.Builder().setTypeExpression(property.getType()).build(); + + jgen.writeFieldName(Constants.VALUE); + primitiveValue(jgen, typeInfo, property.getValue().asPrimitive()); } else if (property.getValue().isEnum()) { jgen.writeStringField(Constants.VALUE, property.getValue().asEnum().get()); } else if (property.getValue().isGeospatial() || property.getValue().isCollection()) { diff --git a/pom.xml b/pom.xml index 247e1934f..108276959 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ --> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.apache.olingo</groupId> @@ -210,6 +210,12 @@ <version>1.5</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <version>${sl4j.version}</version> + <scope>test</scope> + </dependency> </dependencies> </dependencyManagement> @@ -307,6 +313,7 @@ <artifactId>maven-surefire-plugin</artifactId> <version>2.17</version> <configuration> + <redirectTestOutputToFile>true</redirectTestOutputToFile> <runOrder>alphabetical</runOrder> <encoding>UTF-8</encoding> <inputEncoding>UTF-8</inputEncoding> @@ -319,8 +326,12 @@ <artifactId>maven-failsafe-plugin</artifactId> <version>2.17</version> <configuration> - <encoding>utf-8</encoding> + <redirectTestOutputToFile>true</redirectTestOutputToFile> <runOrder>alphabetical</runOrder> + <encoding>UTF-8</encoding> + <inputEncoding>UTF-8</inputEncoding> + <outputEncoding>UTF-8</outputEncoding> + <argLine>-Dfile.encoding=UTF-8</argLine> </configuration> <executions> <execution>