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 fb31f09c4..49b2e4c7a 100644 --- a/fit/src/main/java/org/apache/olingo/fit/V4Services.java +++ b/fit/src/main/java/org/apache/olingo/fit/V4Services.java @@ -345,6 +345,17 @@ public class V4Services extends AbstractServices { return new ByteArrayInputStream(bos.toByteArray()); } + @GET + @Path("/Boss") + public Response getSingletonBoss( + @Context UriInfo uriInfo, + @HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept, + @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format) { + + return getEntityInternal( + uriInfo.getRequestUri().toASCIIString(), accept, "Boss", StringUtils.EMPTY, format, null, null, false); + } + @GET @Path("/Company") public Response getSingletonCompany( 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 bddb01729..58e5772fc 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 @@ -125,6 +125,8 @@ public class DataBinder { properties.add(toJSONProperty((AtomPropertyImpl) property)); } + jsonEntity.getAnnotations().addAll(atomEntity.getAnnotations()); + return jsonEntity; } diff --git a/fit/src/main/resources/V40/Boss/entity.full.json b/fit/src/main/resources/V40/Boss/entity.full.json new file mode 100644 index 000000000..d89b4a58c --- /dev/null +++ b/fit/src/main/resources/V40/Boss/entity.full.json @@ -0,0 +1,46 @@ +{ + "@odata.context": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/$metadata#Boss", + "@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.Customer", + "@odata.id": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/Boss", + "@odata.editLink": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/Boss/Microsoft.Test.OData.Services.ODataWCFService.Customer", + "@Microsoft.Test.OData.Services.ODataWCFService.IsBoss": true, + "PersonID": 2, + "FirstName": "Jill", + "LastName": "Jones", + "MiddleName": null, + "HomeAddress": null, + "Home@odata.type": "#GeographyPoint", + "Home": { + "type": "Point", + "coordinates": [161.8, 15.0], + "crs": { + "type": "name", + "properties": { + "name": "EPSG:4326" + } + } + }, + "Numbers@odata.type": "#Collection(String)", + "Numbers": [], + "Emails@odata.type": "#Collection(String)", + "Emails": [], + "City": "Sydney", + "Birthday@odata.type": "#DateTimeOffset", + "Birthday": "1983-01-15T00:00:00Z", + "TimeBetweenLastTwoOrders@odata.type": "#Duration", + "TimeBetweenLastTwoOrders": "PT0.0000002S", + "Parent@odata.associationLink": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/Boss/Microsoft.Test.OData.Services.ODataWCFService.Customer/Parent/$ref", + "Parent@odata.navigationLink": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/Boss/Microsoft.Test.OData.Services.ODataWCFService.Customer/Parent", + "Orders@odata.associationLink": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/Boss/Microsoft.Test.OData.Services.ODataWCFService.Customer/Orders/$ref", + "Orders@odata.navigationLink": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/Boss/Microsoft.Test.OData.Services.ODataWCFService.Customer/Orders", + "Company@odata.associationLink": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/Boss/Microsoft.Test.OData.Services.ODataWCFService.Customer/Company/$ref", + "Company@odata.navigationLink": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/Boss/Microsoft.Test.OData.Services.ODataWCFService.Customer/Company", + "#Microsoft.Test.OData.Services.ODataWCFService.ResetAddress": { + "title": "Microsoft.Test.OData.Services.ODataWCFService.ResetAddress", + "target": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/Boss/Microsoft.Test.OData.Services.ODataWCFService.Customer/Microsoft.Test.OData.Services.ODataWCFService.ResetAddress" + }, + "#Microsoft.Test.OData.Services.ODataWCFService.GetHomeAddress": { + "title": "Microsoft.Test.OData.Services.ODataWCFService.GetHomeAddress", + "target": "http://localhost:${cargo.servlet.port}/stub/StaticService/V40/Static.svc/Boss/Microsoft.Test.OData.Services.ODataWCFService.Customer/Microsoft.Test.OData.Services.ODataWCFService.GetHomeAddress" + } +} diff --git a/fit/src/main/resources/V40/Boss/entity.xml b/fit/src/main/resources/V40/Boss/entity.xml new file mode 100644 index 000000000..72ccb4c62 --- /dev/null +++ b/fit/src/main/resources/V40/Boss/entity.xml @@ -0,0 +1,51 @@ + + + + http://localhost:9080/stub/StaticService/V40/Static.svc/Boss + + + + + + + + + + 2 + Jill + Jones + + + + + 161.8 15.0 + + + + + Sydney + 1983-01-15T01:00:00+01:00 + PT0.0000002S + + + true + diff --git a/fit/src/main/resources/V40/badRequest.json b/fit/src/main/resources/V40/badRequest.json index fbc0c63e1..a7150b1c2 100644 --- a/fit/src/main/resources/V40/badRequest.json +++ b/fit/src/main/resources/V40/badRequest.json @@ -1,35 +1,24 @@ { - "error": { - "code": "400", - "message": "Bad request.", - "target": "query", - "details": [ - { - - "code": "400", - - "target": "$search" , - - "message": "Microsoft.Data.OData.BadRequest" + "code": "400", + "target": "$search", + "message": "Microsoft.Data.OData.BadRequest" } ], - "innererror": { - - "trace": ["at Microsoft.Data.OData.MediaTypeUtils.GetContentTypeFromSettings....","callmethod2 etc"], - - "context": {"key1":"for debug deployment only"} + "trace": ["at Microsoft.Data.OData.MediaTypeUtils.GetContentTypeFromSettings....", "callmethod2 etc"], + "context": { + "key1": "for debug deployment only" + } } } - } diff --git a/fit/src/main/resources/V40/metadata.xml b/fit/src/main/resources/V40/metadata.xml index 5e7c9c62b..4bb360cb1 100644 --- a/fit/src/main/resources/V40/metadata.xml +++ b/fit/src/main/resources/V40/metadata.xml @@ -22,418 +22,441 @@ + - - - + + + - + - - + - - - - - + + + + + - - - + + + - - - - + + + + - + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - + + + - + - - - - - - - - - + + + + + + + + + - + - - + + - - - - - + + + + + - - + + - - - - + + + + - - - - - - + + + + + + - + - - - - - - - + + + + + + + - - + + - - - - - - - + + + + + + + - + - - - + + + + - + - + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - + - - - + + + - + - - + + - + - - + + - - - + + + - - - + + + - - - - + + + + - - - + + + - + - - + + - - + + + - - + + - - - + + + - - - + + + - + - - + + - - + + - + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - + + - - + + - + - - - - - - - + + + + + + + - + - - - - + + + + + - + - - - - - - + + + + + + - - - - - - + + + + + + - + - - - - + + + + - + - - - - + + + + - + - - - - + + + + - + - - - - - + + + + + - + - + + + - + + - - + + + - + + - + - - + + - + - - - + + + + + + + + + OrderID + + + + + OrderDetails + + + + - - + + - + - - - - + + + + - + - - - - - - - - - - + + + + + + + + + + + - - - + + + - - - + + + - - + \ No newline at end of file diff --git a/fit/src/main/resources/V40/notFound.json b/fit/src/main/resources/V40/notFound.json index 2af461881..3f2d311e4 100644 --- a/fit/src/main/resources/V40/notFound.json +++ b/fit/src/main/resources/V40/notFound.json @@ -1,35 +1,23 @@ { - "error": { - "code": "501", - "message": "Unsupported functionality", - "target": "query", - "details": [ - { - - "code": "301", - - "target": "$search", - - "message": "$search query option not supported" + "code": "301", + "target": "$search", + "message": "$search query option not supported" } ], - "innererror": { - - "trace": ["callmethod1 etc","callmethod2 etc"], - - "context": {"key1":"for debug deployment only"} + "trace": ["callmethod1 etc", "callmethod2 etc"], + "context": { + "key1": "for debug deployment only" + } } - } - } diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/ErrorResponseTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/ErrorResponseTestITCase.java index 7e576f0c0..a9530cc32 100644 --- a/fit/src/test/java/org/apache/olingo/fit/v4/ErrorResponseTestITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/v4/ErrorResponseTestITCase.java @@ -19,11 +19,10 @@ package org.apache.olingo.fit.v4; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import java.net.URI; -import java.util.Dictionary; - +import java.util.Map; import org.apache.olingo.client.api.communication.ODataClientErrorException; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest; import org.apache.olingo.commons.api.domain.ODataError; @@ -34,43 +33,33 @@ import org.junit.Test; public class ErrorResponseTestITCase extends AbstractTestITCase { - @Test - public void jsonError() { + @Test + public void jsonError() { + final URI readURI = getClient().getURIBuilder(testStaticServiceRootURL). + appendEntitySetSegment("Customers").appendKeySegment(32). + build(); - ODataPubFormat format = ODataPubFormat.JSON; - final URI readURI = getClient().getURIBuilder(testStaticServiceRootURL) - .appendEntitySetSegment("Customers").appendKeySegment(32) - .build(); + final ODataEntityRequest req = getClient().getRetrieveRequestFactory().getEntityRequest(readURI); + try { + final ODataEntity read = read(ODataPubFormat.JSON, readURI); - final ODataEntityRequest req = getClient() - .getRetrieveRequestFactory().getEntityRequest(readURI); - try { - final ODataEntity read = read(format, readURI); - } catch (Exception ex) { - ODataError err = ((ODataClientErrorException) ex).getODataError(); + fail("should have got exception"); + } catch (Exception ex) { + final ODataError err = ((ODataClientErrorException) ex).getODataError(); - // verify details - ODataErrorDetail detail = (ODataErrorDetail) err.getDetails() - .get(0); - assertEquals("Code should be correct", "301", detail.getCode()); - assertEquals("Target should be correct", "$search", - detail.getTarget()); - assertEquals("Message should be correct", - "$search query option not supported", detail.getMessage()); + // verify details + final ODataErrorDetail detail = (ODataErrorDetail) err.getDetails().get(0); + assertEquals("Code should be correct", "301", detail.getCode()); + assertEquals("Target should be correct", "$search", detail.getTarget()); + assertEquals("Message should be correct", "$search query option not supported", detail.getMessage()); - // verify inner error dictionary - Dictionary innerErr = err.getInnerError(); - assertEquals("innerError dictionary size should be correct", 2, - innerErr.size()); - assertEquals("innerError['context'] should be correct", - "{\"key1\":\"for debug deployment only\"}", - innerErr.get("context")); - assertEquals("innerError['trace'] should be correct", - "[\"callmethod1 etc\",\"callmethod2 etc\"]", - innerErr.get("trace")); - return; - } - - assertNotNull("should have got exception", null); - } + // verify inner error dictionary + final Map innerErr = err.getInnerError(); + assertEquals("innerError dictionary size should be correct", 2, innerErr.size()); + assertEquals("innerError['context'] should be correct", + "{\"key1\":\"for debug deployment only\"}", innerErr.get("context")); + assertEquals("innerError['trace'] should be correct", + "[\"callmethod1 etc\",\"callmethod2 etc\"]", innerErr.get("trace")); + } + } } diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/MetadataTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/MetadataTestITCase.java index 4a2143701..6db180465 100644 --- a/fit/src/test/java/org/apache/olingo/fit/v4/MetadataTestITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/v4/MetadataTestITCase.java @@ -20,6 +20,7 @@ package org.apache.olingo.fit.v4; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.apache.olingo.commons.api.edm.Edm; @@ -28,35 +29,56 @@ import org.apache.olingo.commons.api.edm.EdmEntityContainer; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmEnumType; +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmSchema; import org.apache.olingo.commons.api.edm.EdmTerm; import org.apache.olingo.commons.api.edm.EdmTypeDefinition; import org.apache.olingo.commons.api.edm.FullQualifiedName; +import org.apache.olingo.commons.api.edm.annotation.EdmRecord; import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean; import org.junit.Test; public class MetadataTestITCase extends AbstractTestITCase { @Test - public void retrieve() { - final Edm metadata = client.getRetrieveRequestFactory(). - getMetadataRequest(testStaticServiceRootURL).execute().getBody(); - assertNotNull(metadata); + public void retrieve() throws EdmPrimitiveTypeException { + final Edm edm = client.getRetrieveRequestFactory().getMetadataRequest(testStaticServiceRootURL).execute().getBody(); + assertNotNull(edm); - final EdmEntityType order = metadata.getEntityType( + final EdmEntityType order = edm.getEntityType( new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService", "Order")); assertNotNull(order); final EdmProperty orderDate = order.getStructuralProperty("OrderDate"); assertNotNull(orderDate); assertEquals("Edm.DateTimeOffset", orderDate.getType().getFullQualifiedName().toString()); + + final EdmTerm isBoss = edm.getTerm(new FullQualifiedName(edm.getSchemas().get(0).getNamespace(), "IsBoss")); + assertNotNull(isBoss); + assertEquals(EdmBoolean.getInstance(), isBoss.getType()); + + final EdmEntitySet orders = edm.getSchemas().get(0).getEntityContainer().getEntitySet("Orders"); + assertNotNull(orders); + assertFalse(orders.getAnnotations().isEmpty()); + assertTrue(orders.getAnnotations().get(0).getExpression().isDynamic()); + assertTrue(orders.getAnnotations().get(0).getExpression().asDynamic().isRecord()); + final EdmRecord record = orders.getAnnotations().get(0).getExpression().asDynamic().asRecord(); + assertNotNull(record); + assertEquals(3, record.getPropertyValues().size()); + assertTrue(record.getPropertyValues().get(0).getValue().isConstant()); + assertTrue(record.getPropertyValues().get(0).getValue().asConstant().getValue().asPrimitive(). + toCastValue(Boolean.class)); + assertTrue(record.getPropertyValues().get(1).getValue().asDynamic().isCollection()); + assertEquals(1, record.getPropertyValues().get(1).getValue().asDynamic().asCollection().getItems().size()); + assertTrue(record.getPropertyValues().get(1).getValue().asDynamic().asCollection().getItems().get(0).isDynamic()); + assertEquals("OrderID", record.getPropertyValues().get(1).getValue().asDynamic().asCollection(). + getItems().get(0).asDynamic().asPropertyPath().getValue()); } @Test public void include() { - final Edm edm = client.getRetrieveRequestFactory(). - getMetadataRequest(testNorthwindRootURL).execute().getBody(); + final Edm edm = client.getRetrieveRequestFactory().getMetadataRequest(testNorthwindRootURL).execute().getBody(); assertNotNull(edm); final EdmEntityContainer container = edm.getEntityContainer( diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/SingletonTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/SingletonTestITCase.java index 4d2df429a..64e7f7103 100644 --- a/fit/src/test/java/org/apache/olingo/fit/v4/SingletonTestITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/v4/SingletonTestITCase.java @@ -20,6 +20,7 @@ package org.apache.olingo.fit.v4; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.net.URI; @@ -29,6 +30,7 @@ import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRe import org.apache.olingo.client.api.communication.response.ODataEntityUpdateResponse; import org.apache.olingo.client.api.uri.v4.URIBuilder; import org.apache.olingo.client.api.v4.ODataClient; +import org.apache.olingo.commons.api.domain.v4.ODataAnnotation; import org.apache.olingo.commons.api.domain.v4.ODataValuable; import org.apache.olingo.commons.api.domain.v4.Singleton; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; @@ -55,12 +57,12 @@ public class SingletonTestITCase extends AbstractTestITCase { } @Test - public void readfromAtom() throws EdmPrimitiveTypeException { + public void readFromAtom() throws EdmPrimitiveTypeException { read(client, ODataPubFormat.ATOM); } @Test - public void readfromJSON() throws EdmPrimitiveTypeException { + public void readFromJSON() throws EdmPrimitiveTypeException { read(edmClient, ODataPubFormat.JSON); } @@ -69,6 +71,37 @@ public class SingletonTestITCase extends AbstractTestITCase { read(client, ODataPubFormat.JSON_FULL_METADATA); } + private void readWithAnnotations(final ODataClient client, final ODataPubFormat format) + throws EdmPrimitiveTypeException { + + final URIBuilder builder = client.getURIBuilder(testStaticServiceRootURL).appendSingletonSegment("Boss"); + final ODataEntityRequest singleton = + client.getRetrieveRequestFactory().getSingletonRequest(builder.build()); + singleton.setFormat(format); + singleton.setPrefer(client.newPreferences().includeAnnotations("*")); + final Singleton boss = singleton.execute().getBody(); + assertNotNull(boss); + + assertFalse(boss.getAnnotations().isEmpty()); + final ODataAnnotation isBoss = boss.getAnnotations().get(0); + assertTrue(isBoss.getPrimitiveValue().toCastValue(Boolean.class)); + } + + @Test + public void readWithAnnotationsFromAtom() throws EdmPrimitiveTypeException { + readWithAnnotations(client, ODataPubFormat.ATOM); + } + + @Test + public void readWithAnnotationsFromJSON() throws EdmPrimitiveTypeException { + readWithAnnotations(edmClient, ODataPubFormat.JSON); + } + + @Test + public void readWithAnnotationsFromJSONFull() throws EdmPrimitiveTypeException { + readWithAnnotations(client, ODataPubFormat.JSON_FULL_METADATA); + } + private void update(final ODataPubFormat format) throws EdmPrimitiveTypeException { final Singleton changes = getClient().getObjectFactory().newSingleton( new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService.Company")); diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/edm/v4/annotation/EdmRecordImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/edm/v4/annotation/EdmRecordImpl.java index 270cf87e5..e01f7b039 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/edm/v4/annotation/EdmRecordImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/edm/v4/annotation/EdmRecordImpl.java @@ -32,14 +32,16 @@ public class EdmRecordImpl extends AbstractEdmAnnotatableDynamicAnnotationExpres private final List propertyValues; - private final EdmStructuredType type; + private EdmStructuredType type; public EdmRecordImpl(final Edm edm, final String type, final List propertyValues) { this.edm = edm; this.propertyValues = propertyValues; - final EdmTypeInfo typeInfo = new EdmTypeInfo.Builder().setEdm(edm).setTypeExpression(type).build(); - this.type = typeInfo.getEntityType() == null ? typeInfo.getComplexType() : typeInfo.getEntityType(); + if (type != null) { + final EdmTypeInfo typeInfo = new EdmTypeInfo.Builder().setEdm(edm).setTypeExpression(type).build(); + this.type = typeInfo.getEntityType() == null ? typeInfo.getComplexType() : typeInfo.getEntityType(); + } } @Override diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java index a4a38ea4e..05279517f 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java @@ -145,6 +145,7 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder final Annotation annotation = new AnnotationImpl(); annotation.setTerm(odataAnnotation.getTerm()); + annotation.setType(odataAnnotation.getValue().getTypeName()); updateValuable(annotation, odataAnnotation, reference); annotatable.getAnnotations().add(annotation); @@ -230,8 +231,16 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder } } + if (fqn == null && annotation.getType() != null) { + final EdmTypeInfo typeInfo = new EdmTypeInfo.Builder().setTypeExpression(annotation.getType()).build(); + if (typeInfo.isPrimitiveType()) { + fqn = typeInfo.getPrimitiveTypeKind().getFullQualifiedName(); + } + } + final ODataAnnotation odataAnnotation = new ODataAnnotationImpl(annotation.getTerm(), (org.apache.olingo.commons.api.domain.v4.ODataValue) getODataValue(fqn, annotation, null, null)); + odataAnnotatable.getAnnotations().add(odataAnnotation); } } @@ -278,7 +287,7 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder final ODataProperty property = new ODataPropertyImpl(resource.getPayload().getName(), getODataValue(typeInfo == null ? null : typeInfo.getFullQualifiedName(), - resource.getPayload(), resource.getContextURL(), resource.getMetadataETag())); + resource.getPayload(), resource.getContextURL(), resource.getMetadataETag())); odataAnnotations(resource.getPayload(), property); return property; diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java index a9e0b06a6..2edab5ec9 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java @@ -246,8 +246,8 @@ public interface Constants { public static final String ERROR_TARGET = "target"; public static final String ERROR_DETAILS = "details"; - - public static final String ERROR_INNERERROR= "innererror"; + + public static final String ERROR_INNERERROR = "innererror"; // canonical functions to be applied via dynamic annotation Apply public static final String CANONICAL_FUNCTION_CONCAT = "odata.concat"; diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataError.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataError.java index f899d9aea..1d2b83eb8 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataError.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataError.java @@ -18,8 +18,8 @@ */ package org.apache.olingo.commons.api.domain; -import java.util.Dictionary; import java.util.List; +import java.util.Map; /** * OData error. @@ -46,7 +46,6 @@ public interface ODataError { * @return error message. */ String getTarget(); - /** * Gets error details. @@ -58,7 +57,7 @@ public interface ODataError { /** * Gets server defined key-value pairs for debug environment only. * - * @return a Dictionary representing server defined object. + * @return a pair representing server defined object. */ - Dictionary getInnerError(); + Map getInnerError(); } diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataErrorDetail.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataErrorDetail.java index 462e91e84..48985e53e 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataErrorDetail.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/ODataErrorDetail.java @@ -19,9 +19,9 @@ package org.apache.olingo.commons.api.domain; /** - * OData details, for example - { "error": {..., "details":[ + * OData details, for example { "error": {..., "details":[ * {"code": "301","target": "$search" ,"message": "$search query option not supported"} - * ],...}} + * ],...}}. */ public interface ODataErrorDetail { 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 2401a0944..bb115cfca 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 @@ -209,7 +209,7 @@ abstract class AbstractJsonSerializer extends ODataJacksonSerializer { } protected void valuable(final JsonGenerator jgen, final Valuable valuable, final String name) throws IOException { - if (serverMode && !Constants.VALUE.equals(name)) { + if (serverMode && !Constants.VALUE.equals(name) && !(valuable instanceof Annotation)) { String type = valuable.getType(); if (StringUtils.isBlank(type) && valuable.getValue().isPrimitive() || valuable.getValue().isNull()) { type = EdmPrimitiveTypeKind.String.getFullQualifiedName().toString(); diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractODataError.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractODataError.java index 62cbebf27..1e9cf519d 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractODataError.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractODataError.java @@ -18,30 +18,22 @@ */ package org.apache.olingo.commons.core.data; -import java.util.Dictionary; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import org.apache.olingo.commons.api.domain.ODataError; import org.apache.olingo.commons.api.domain.ODataErrorDetail; -// { -// "error": { -// "code": "501", -// "message": "Unsupported functionality", -// "target": "query", -// "details": [ -// { -// "code": "301", -// "target": "$search", -// "message": "$search query option not supported" -// } -// ], -// "innererror": { -// "trace": [...], -// "context": {...} -// } -// } -// } +/** + * Example: + * + * { + * "error": { "code": "501", "message": "Unsupported functionality", "target": "query", "details": [ { "code": "301", + * "target": "$search", "message": "$search query option not supported" } ], "innererror": { "trace": [...], "context": + * {...} } } } + * . + */ public abstract class AbstractODataError implements ODataError { private String code; @@ -51,9 +43,9 @@ public abstract class AbstractODataError implements ODataError { private String target; private List details; - - private Dictionary innerError; - + + private Map innerError = new LinkedHashMap(); + @Override public String getCode() { return code; @@ -91,11 +83,7 @@ public abstract class AbstractODataError implements ODataError { } @Override - public Dictionary getInnerError() { + public Map getInnerError() { return innerError; } - - public void setInnerError(final Dictionary innerError) { - this.innerError = innerError; - } } diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDeserializer.java index 50fa1f9b2..36818a9e5 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDeserializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDeserializer.java @@ -24,17 +24,12 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; - import java.io.IOException; import java.net.URI; import java.util.ArrayList; -import java.util.Dictionary; -import java.util.Hashtable; import java.util.Iterator; import java.util.List; - import org.apache.olingo.commons.api.Constants; -import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.ResWrap; import org.apache.olingo.commons.api.domain.ODataErrorDetail; @@ -65,29 +60,25 @@ public class JSONODataErrorDeserializer extends AbstractJsonDeserializer details = new ArrayList(); - for (final Iterator itor = errorNode.get(Constants.ERROR_DETAILS).iterator(); itor.hasNext();) { - details.add( - itor.next().traverse(parser.getCodec()).>readValueAs( - new TypeReference() { - }).getPayload()); - } - - error.setDetails(details); + final List details = new ArrayList(); + for (final Iterator itor = errorNode.get(Constants.ERROR_DETAILS).iterator(); itor.hasNext();) { + details.add(itor.next().traverse(parser.getCodec()).>readValueAs( + new TypeReference() { + }).getPayload()); + } + + error.setDetails(details); } if (errorNode.hasNonNull(Constants.ERROR_INNERERROR)) { - JsonNode innerError = errorNode.get(Constants.ERROR_INNERERROR); - Dictionary innerErr = new Hashtable(); - for (final Iterator itor = innerError.fieldNames(); itor.hasNext();) { - String keyTmp = itor.next(); - String val = innerError.get(keyTmp).toString(); - innerErr.put(keyTmp,val); - } - - error.setInnerError(innerErr); + final JsonNode innerError = errorNode.get(Constants.ERROR_INNERERROR); + for (final Iterator itor = innerError.fieldNames(); itor.hasNext();) { + final String keyTmp = itor.next(); + final String val = innerError.get(keyTmp).toString(); + error.getInnerError().put(keyTmp, val); + } } } - + return new ResWrap((URI) null, null, error); } } diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDetailDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDetailDeserializer.java index 9c2ce7bb5..38ea04342 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDetailDeserializer.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDetailDeserializer.java @@ -20,47 +20,37 @@ package org.apache.olingo.commons.core.data; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - import java.io.IOException; import java.net.URI; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - import org.apache.olingo.commons.api.Constants; -import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.ResWrap; -import org.apache.olingo.commons.api.domain.ODataErrorDetail; -public class JSONODataErrorDetailDeserializer extends - AbstractJsonDeserializer { +public class JSONODataErrorDetailDeserializer extends AbstractJsonDeserializer { - @Override - protected ResWrap doDeserialize( - final JsonParser parser, final DeserializationContext ctxt) - throws IOException, JsonProcessingException { + @Override + protected ResWrap doDeserialize( + final JsonParser parser, final DeserializationContext ctxt) + throws IOException, JsonProcessingException { - final JSONODataErrorDetailImpl error = new JSONODataErrorDetailImpl(); - final JsonNode errorNode = parser.getCodec().readTree(parser); - if (errorNode.has(Constants.ERROR_CODE)) { - error.setCode(errorNode.get(Constants.ERROR_CODE).textValue()); - } - if (errorNode.has(Constants.ERROR_MESSAGE)) { - final JsonNode message = errorNode.get(Constants.ERROR_MESSAGE); - if (message.isValueNode()) { - error.setMessage(message.textValue()); - } else if (message.isObject()) { - error.setMessage(message.get(Constants.VALUE).asText()); - } - } - if (errorNode.has(Constants.ERROR_TARGET)) { - error.setTarget(errorNode.get(Constants.ERROR_TARGET).textValue()); - } + final JSONODataErrorDetailImpl error = new JSONODataErrorDetailImpl(); + final JsonNode errorNode = parser.getCodec().readTree(parser); + if (errorNode.has(Constants.ERROR_CODE)) { + error.setCode(errorNode.get(Constants.ERROR_CODE).textValue()); + } + if (errorNode.has(Constants.ERROR_MESSAGE)) { + final JsonNode message = errorNode.get(Constants.ERROR_MESSAGE); + if (message.isValueNode()) { + error.setMessage(message.textValue()); + } else if (message.isObject()) { + error.setMessage(message.get(Constants.VALUE).asText()); + } + } + if (errorNode.has(Constants.ERROR_TARGET)) { + error.setTarget(errorNode.get(Constants.ERROR_TARGET).textValue()); + } - return new ResWrap((URI) null, null, error); - } + return new ResWrap((URI) null, null, error); + } } diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDetailImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDetailImpl.java index 2f4585aaf..49f31593a 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDetailImpl.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/JSONODataErrorDetailImpl.java @@ -27,36 +27,36 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @JsonDeserialize(using = JSONODataErrorDetailDeserializer.class) public class JSONODataErrorDetailImpl implements ODataErrorDetail { - private String code; + private String code; - private String message; + private String message; - private String target; + private String target; - @Override - public String getCode() { - return code; - } + @Override + public String getCode() { + return code; + } - public void setCode(final String code) { - this.code = code; - } + public void setCode(final String code) { + this.code = code; + } - @Override - public String getMessage() { - return message; - } + @Override + public String getMessage() { + return message; + } - public void setMessage(final String message) { - this.message = message; - } + public void setMessage(final String message) { + this.message = message; + } - @Override - public String getTarget() { - return target; - } + @Override + public String getTarget() { + return target; + } - public void setTarget(final String target) { - this.target = target; - } -} \ No newline at end of file + public void setTarget(final String target) { + this.target = target; + } +}