This is an automated email from the ASF dual-hosted git repository. ramyav pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/olingo-odata2.git
The following commit(s) were added to refs/heads/master by this push: new f7679dc [OLINGO-1494]OData V2: Serialize error details f7679dc is described below commit f7679dc94491d4aa2a5146df94038565f721ef59 Author: ramya vasanth <ramya.vasa...@sap.com> AuthorDate: Thu Nov 19 14:49:54 2020 +0530 [OLINGO-1494]OData V2: Serialize error details --- .../odata2/api/processor/ODataErrorContext.java | 67 ++++++++++++++++++++-- .../olingo/odata2/core/ep/AtomEntityProvider.java | 23 +++++++- .../core/ep/ContentTypeBasedEntityProvider.java | 2 + .../olingo/odata2/core/ep/JsonEntityProvider.java | 23 +++++++- .../olingo/odata2/core/ep/ProviderFacadeImpl.java | 3 +- .../ep/producer/JsonErrorDocumentProducer.java | 43 +++++++++++--- .../core/ep/producer/XmlErrorDocumentProducer.java | 58 ++++++++++++++++--- .../olingo/odata2/core/ep/util/FormatJson.java | 3 + .../olingo/odata2/core/ep/util/FormatXml.java | 4 ++ .../core/ep/producer/JsonErrorProducerTest.java | 39 +++++++++++++ .../core/ep/producer/XmlErrorProducerTest.java | 60 ++++++++++++++++++- 11 files changed, 298 insertions(+), 27 deletions(-) diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataErrorContext.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataErrorContext.java index 70527be..881c352 100644 --- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataErrorContext.java +++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataErrorContext.java @@ -19,6 +19,8 @@ package org.apache.olingo.odata2.api.processor; import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -36,16 +38,24 @@ import org.apache.olingo.odata2.api.uri.PathInfo; */ public class ODataErrorContext { + // General purpose attributes private String contentType; private HttpStatusCodes httpStatus; - private String errorCode; - private String message; - private Locale locale; private Exception exception; private Map<String, List<String>> requestHeaders; + private PathInfo pathInfo; private URI requestUri; + + // Standard OData Error Response + private String errorCode; + private Locale locale; + private String message; private String innerError; - private PathInfo pathInfo; + + // Extended OData Error Response + private String severity; + private String target; + private Collection<ODataErrorContext> errorDetails = new ArrayList<ODataErrorContext>(); /** * create a new context object @@ -119,6 +129,22 @@ public class ODataErrorContext { } /** + * Return OData severity that is returned in error response. + * @return an application defined severity + */ + public String getSeverity() { + return severity; +} + + /** + * Set OData severity that should be returned in error response. + * @param severity an application defined severity + */ + public void setSeverity(String severity) { + this.severity = severity; + } + +/** * Return a translated error message. * @return translated message */ @@ -209,6 +235,39 @@ public class ODataErrorContext { } /** + * Get a collection of detailed errors for a OData inner error to be returned in error response. + * @return a inner error message + */ + public Collection<ODataErrorContext> getErrorDetails() { + return errorDetails; + } + + /** + * Get a target of detailed error for a OData inner error to be returned in error response. + * @return a target + */ + public String getTarget() { + return target; + } + + /** + * Set a target for a OData detailed error to be returned in error response. + * @param target a target + */ + public void setTarget(String target) { + this.target = target; + } + +/** + * Set a collection of detailed errors for a OData inner error to be returned in error response. + * If set, will overwrite the <code>innerError</code> element. + * @param errorDetails a inner error message + */ + public void setErrorDetails(Collection<ODataErrorContext> errorDetails) { + this.errorDetails = errorDetails; + } + + /** * Get {@link PathInfo} object. * May be <code>NULL</code> if no path info was created/set till error occurred (but may be over written by * application). diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/AtomEntityProvider.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/AtomEntityProvider.java index 201ffc7..4576ce5 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/AtomEntityProvider.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/AtomEntityProvider.java @@ -103,6 +103,25 @@ public class AtomEntityProvider implements ContentTypeBasedEntityProvider { @Override public ODataResponse writeErrorDocument(final HttpStatusCodes status, final String errorCode, final String message, final Locale locale, final String innerError) { + ODataErrorContext context = new ODataErrorContext(); + context.setHttpStatus(status); + context.setErrorCode(errorCode); + context.setMessage(message); + context.setLocale(locale); + context.setInnerError(innerError); + + return writeErrorDocument(context); + } + + /** + * <p>Serializes an error message according to the OData standard.</p> + * <p>In case an error occurs, it is logged. + * An exception is not thrown because this method is used in exception handling.</p> + * @param context the {@link ODataErrorContext} associated with this error + * @return an {@link ODataResponse} containing the serialized error message + */ + @Override + public ODataResponse writeErrorDocument(ODataErrorContext context) { CircleStreamBuffer csb = new CircleStreamBuffer(); try { @@ -110,14 +129,14 @@ public class AtomEntityProvider implements ContentTypeBasedEntityProvider { XMLStreamWriter writer = XmlHelper.getXMLOutputFactory().createXMLStreamWriter(outStream, DEFAULT_CHARSET); XmlErrorDocumentProducer producer = new XmlErrorDocumentProducer(); - producer.writeErrorDocument(writer, errorCode, message, locale, innerError); + producer.writeErrorDocument(writer, context); writer.flush(); csb.closeWrite(); ODataResponseBuilder response = ODataResponse.entity(csb.getInputStream()) .header(ODataHttpHeaders.DATASERVICEVERSION, ODataServiceVersion.V10) - .status(status); + .status(context.getHttpStatus()); return response.build(); } catch (Exception e) { csb.close(); diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ContentTypeBasedEntityProvider.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ContentTypeBasedEntityProvider.java index 249931d..2cd2479 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ContentTypeBasedEntityProvider.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ContentTypeBasedEntityProvider.java @@ -81,6 +81,8 @@ public interface ContentTypeBasedEntityProvider { ODataResponse writeErrorDocument(HttpStatusCodes status, String errorCode, String message, Locale locale, String innerError); + ODataResponse writeErrorDocument(ODataErrorContext context); + ServiceDocument readServiceDocument(InputStream serviceDocument) throws EntityProviderException; ODataDeltaFeed readDeltaFeed(EdmEntitySet entitySet, InputStream content, EntityProviderReadProperties properties) diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java index fa94320..1d87012 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java @@ -85,15 +85,34 @@ public class JsonEntityProvider implements ContentTypeBasedEntityProvider { @Override public ODataResponse writeErrorDocument(final HttpStatusCodes status, final String errorCode, final String message, final Locale locale, final String innerError) { + ODataErrorContext context = new ODataErrorContext(); + context.setHttpStatus(status); + context.setErrorCode(errorCode); + context.setMessage(message); + context.setLocale(locale); + context.setInnerError(innerError); + + return writeErrorDocument(context); + } + + /** + * <p>Serializes an error message according to the OData standard.</p> + * <p>In case an error occurs, it is logged. + * An exception is not thrown because this method is used in exception handling.</p> + * @param context the {@link ODataErrorContext} associated with this error + * @return an {@link ODataResponse} containing the serialized error message + */ + @Override + public ODataResponse writeErrorDocument(ODataErrorContext context) { CircleStreamBuffer buffer = new CircleStreamBuffer(); try { BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET)); - new JsonErrorDocumentProducer().writeErrorDocument(writer, errorCode, message, locale, innerError); + new JsonErrorDocumentProducer().writeErrorDocument(writer, context); writer.flush(); buffer.closeWrite(); - return ODataResponse.status(status) + return ODataResponse.status(context.getHttpStatus()) .entity(buffer.getInputStream()) .header(ODataHttpHeaders.DATASERVICEVERSION, ODataServiceVersion.V10) .build(); diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java index 9acf487..01a564d 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java @@ -87,8 +87,7 @@ public class ProviderFacadeImpl implements EntityProviderInterface { @Override public ODataResponse writeErrorDocument(final ODataErrorContext context) { try { - return create(context.getContentType()).writeErrorDocument(context.getHttpStatus(), context.getErrorCode(), - context.getMessage(), context.getLocale(), context.getInnerError()); + return create(context.getContentType()).writeErrorDocument(context); } catch (EntityProviderException e) { throw new ODataRuntimeException(e); } diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorDocumentProducer.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorDocumentProducer.java index 54b5760..c838886 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorDocumentProducer.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorDocumentProducer.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.io.Writer; import java.util.Locale; +import org.apache.olingo.odata2.api.processor.ODataErrorContext; import org.apache.olingo.odata2.core.ep.util.FormatJson; import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter; @@ -32,13 +33,25 @@ public class JsonErrorDocumentProducer { public void writeErrorDocument(final Writer writer, final String errorCode, final String message, final Locale locale, final String innerError) throws IOException { - JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer); + ODataErrorContext context = new ODataErrorContext(); + context.setErrorCode(errorCode); + context.setMessage(message); + context.setLocale(locale); + context.setInnerError(innerError); + + writeErrorDocument(writer, context); + } + public void writeErrorDocument(final Writer writer, ODataErrorContext context) throws IOException { + Locale locale = context.getLocale(); + String innerError = context.getInnerError(); + + JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer); jsonStreamWriter .beginObject() .name(FormatJson.ERROR) .beginObject() - .namedStringValue(FormatJson.CODE, errorCode) + .namedStringValue(FormatJson.CODE, context.getErrorCode()) .separator() .name(FormatJson.MESSAGE) .beginObject() @@ -48,12 +61,28 @@ public class JsonErrorDocumentProducer { locale.getLanguage() + (locale.getCountry() == null || locale.getCountry().isEmpty() ? "" : ("-" + locale.getCountry()))) .separator() - .namedStringValue(FormatJson.VALUE, message) + .namedStringValue(FormatJson.VALUE, context.getMessage()) .endObject(); - if (innerError != null) { - jsonStreamWriter.separator() - .namedStringValue(FormatJson.INNER_ERROR, innerError); - } + if (!context.getErrorDetails().isEmpty()) { + int cntr = 0; + jsonStreamWriter.separator().name(FormatJson.INNER_ERROR).beginObject().name(FormatJson.ERROR_DETAILS) + .beginArray(); + for (ODataErrorContext detail : context.getErrorDetails()) { + if (cntr > 0) { + jsonStreamWriter.separator(); + } + cntr++; + jsonStreamWriter.beginObject() + .namedStringValue(FormatJson.CODE, detail.getErrorCode()).separator() + .namedStringValue(FormatJson.MESSAGE, detail.getMessage()).separator() + .namedStringValue(FormatJson.TARGET, detail.getTarget()).separator() + .namedStringValue(FormatJson.SEVERITY, detail.getSeverity()) + .endObject(); + } + jsonStreamWriter.endArray().endObject(); + } else if (innerError != null) { + jsonStreamWriter.separator().namedStringValue(FormatJson.INNER_ERROR, innerError); + } jsonStreamWriter.endObject() .endObject(); } diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java index 05ee992..e5ff2fd 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java @@ -18,26 +18,40 @@ ******************************************************************************/ package org.apache.olingo.odata2.core.ep.producer; +import java.util.Collection; import java.util.Locale; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import org.apache.olingo.odata2.api.edm.Edm; +import org.apache.olingo.odata2.api.processor.ODataErrorContext; import org.apache.olingo.odata2.core.ep.util.FormatXml; public class XmlErrorDocumentProducer { public void writeErrorDocument(final XMLStreamWriter writer, final String errorCode, final String message, final Locale locale, final String innerError) throws XMLStreamException { + ODataErrorContext context = new ODataErrorContext(); + context.setErrorCode(errorCode); + context.setMessage(message); + context.setLocale(locale); + context.setInnerError(innerError); + + writeErrorDocument(writer, context); + } + + public void writeErrorDocument(final XMLStreamWriter writer, ODataErrorContext context) throws XMLStreamException { + Locale locale = context.getLocale(); + String errorCode = context.getErrorCode(); + String message = context.getMessage(); + String innerError = context.getInnerError(); + Collection<ODataErrorContext> errorDetails = context.getErrorDetails(); + writer.writeStartDocument(); writer.writeStartElement(FormatXml.M_ERROR); writer.writeDefaultNamespace(Edm.NAMESPACE_M_2007_08); - writer.writeStartElement(FormatXml.M_CODE); - if (errorCode != null) { - writer.writeCharacters(errorCode); - } - writer.writeEndElement(); + writeSimpleElement(writer, FormatXml.M_CODE, errorCode); writer.writeStartElement(FormatXml.M_MESSAGE); if (locale != null) { writer.writeAttribute(Edm.PREFIX_XML, Edm.NAMESPACE_XML_1998, FormatXml.XML_LANG, getLocale(locale)); @@ -49,15 +63,33 @@ public class XmlErrorDocumentProducer { } writer.writeEndElement(); - if (innerError != null) { - writer.writeStartElement(FormatXml.M_INNER_ERROR); - writer.writeCharacters(innerError); - writer.writeEndElement(); + if (!errorDetails.isEmpty()) { + writeErrorDetails(writer, errorDetails); + } else if (innerError != null) { + writeSimpleElement(writer, FormatXml.M_INNER_ERROR, innerError); } writer.writeEndDocument(); } + private void writeErrorDetails(final XMLStreamWriter writer, Collection<ODataErrorContext> errorDetails) + throws XMLStreamException { + writer.writeStartElement(FormatXml.M_INNER_ERROR); + writer.writeStartElement(FormatXml.M_ERROR_DETAILS); + for (ODataErrorContext detail : errorDetails) { + writer.writeStartElement(FormatXml.M_ERROR_DETAIL); + + writeSimpleElement(writer, FormatXml.M_CODE, detail.getErrorCode()); + writeSimpleElement(writer, FormatXml.M_MESSAGE, detail.getMessage()); + writeSimpleElement(writer, FormatXml.M_TARGET, detail.getTarget()); + writeSimpleElement(writer, FormatXml.M_SEVERITY, detail.getSeverity()); + + writer.writeEndElement(); + } + writer.writeEndElement(); + writer.writeEndElement(); + } + /** * Gets language and country as defined in RFC 4646 based on {@link Locale}. */ @@ -69,4 +101,12 @@ public class XmlErrorDocumentProducer { } } + private void writeSimpleElement(final XMLStreamWriter writer, String elementName, String value) + throws XMLStreamException { + writer.writeStartElement(elementName); + if (null != value) { + writer.writeCharacters(value); + } + writer.writeEndElement(); + } } diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java index f1010c0..7b36ef8 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java @@ -46,9 +46,12 @@ public class FormatJson { public static final String ERROR = "error"; public static final String CODE = "code"; public static final String MESSAGE = "message"; + public static final String TARGET = "target"; + public static final String SEVERITY = "severity"; public static final String LANG = "lang"; public static final String VALUE = "value"; public static final String INNER_ERROR = "innererror"; + public static final String ERROR_DETAILS = "errordetails"; public static final String DELTA = "__delta"; public static final String ODATA_CONTEXT = "@odata.context"; public static final String DELTA_CONTEXT_PREFIX = "$metadata#"; diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java index 8ad0181..058093d 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java @@ -40,9 +40,13 @@ public class FormatXml { public static final String M_INLINE = "inline"; public static final String M_ERROR = "error"; + public static final String M_SEVERITY = "severity"; + public static final String M_TARGET = "target"; public static final String M_CODE = "code"; public static final String M_MESSAGE = "message"; public static final String M_INNER_ERROR = "innererror"; + public static final String M_ERROR_DETAILS = "errordetails"; + public static final String M_ERROR_DETAIL = "errordetail"; public static final String D_ELEMENT = "element"; public static final String D_LINKS = "links"; diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorProducerTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorProducerTest.java index 29f1e95..8feea0b 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorProducerTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorProducerTest.java @@ -22,6 +22,7 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; import java.io.InputStream; +import java.util.Arrays; import java.util.Locale; import org.apache.olingo.odata2.api.ODataServiceVersion; @@ -55,6 +56,44 @@ public class JsonErrorProducerTest { testSerializeJSON(null, null, null); } + @Test + public void jsonSerializationWithDetails() throws Exception { + String errorCode = "500"; + String message = "Main message"; + Locale locale = Locale.GERMAN; + String innerError = "Inner Error"; + + ODataErrorContext detailed1 = new ODataErrorContext(); + detailed1.setErrorCode("500"); + detailed1.setMessage("Detailed message"); + detailed1.setSeverity("error"); + detailed1.setTarget("element1"); + + ODataErrorContext detailed2 = new ODataErrorContext(); + detailed2.setErrorCode("404"); + detailed2.setMessage("Detailed message 2"); + detailed2.setSeverity("warn"); + detailed2.setTarget("element2"); + + ODataErrorContext ctx = new ODataErrorContext(); + ctx.setContentType(HttpContentType.APPLICATION_JSON); + ctx.setErrorCode(errorCode); + ctx.setHttpStatus(HttpStatusCodes.INTERNAL_SERVER_ERROR); + ctx.setLocale(locale); + ctx.setMessage(message); + ctx.setInnerError(innerError); + ctx.setErrorDetails(Arrays.asList(detailed1, detailed2)); + + ODataResponse response = new ProviderFacadeImpl().writeErrorDocument(ctx); + final String jsonErrorMessage = StringHelper.inputStreamToString((InputStream) response.getEntity()); + assertEquals(jsonErrorMessage, + "{\"error\":{\"code\":\"500\",\"message\":{\"lang\":\"de\",\"value\":\"Main message\"}," + + "\"innererror\":" + + "{\"errordetails\":[" + + "{\"code\":\"500\",\"message\":\"Detailed message\",\"target\":\"element1\",\"severity\":\"error\"}," + + "{\"code\":\"404\",\"message\":\"Detailed message 2\",\"target\":\"element2\",\"severity\":\"warn\"}]}}}"); + } + // helper method private void testSerializeJSON(final String errorCode, final String message, final Locale locale) throws Exception { ODataErrorContext ctx = new ODataErrorContext(); diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorProducerTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorProducerTest.java index 85538ce..9aa88f5 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorProducerTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorProducerTest.java @@ -27,6 +27,7 @@ import static org.junit.Assert.assertNull; import java.io.IOException; import java.io.InputStream; +import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -149,6 +150,38 @@ public class XmlErrorProducerTest extends AbstractXmlProducerTestHelper { } @Test + public void withErrorDetails() throws Exception { + String errorCode = "500"; + String message = "Main message"; + String detailedMessage = "Detailed message"; + String severity = "error"; + String target = "element1"; + Locale locale = Locale.GERMAN; + String innerError = "Inner Error"; + + ODataErrorContext detailed = new ODataErrorContext(); + detailed.setErrorCode(errorCode); + detailed.setMessage(detailedMessage); + detailed.setSeverity(severity); + detailed.setTarget(target); + + ODataErrorContext ctx = new ODataErrorContext(); + ctx.setContentType(contentType); + ctx.setErrorCode(errorCode); + ctx.setHttpStatus(expectedStatus); + ctx.setLocale(locale); + ctx.setMessage(message); + ctx.setInnerError(innerError); + ctx.setErrorDetails(Collections.singletonList(detailed)); + + ODataResponse response = new ProviderFacadeImpl().writeErrorDocument(ctx); + String errorXml = verifyResponse(response); + System.out.println(errorXml); + verifyXml(errorCode, message, locale, innerError, errorXml); + verifyDetailsXml(errorCode, detailedMessage, severity, target, errorXml); + } + + @Test public void normal() throws Exception { serializeError(null, "Message", null, Locale.GERMAN); serializeError(null, "Message", null, Locale.ENGLISH); @@ -222,8 +255,14 @@ public class XmlErrorProducerTest extends AbstractXmlProducerTestHelper { private void serializeError(final String errorCode, final String message, final String innerError, final Locale locale) throws Exception { + ODataErrorContext context = new ODataErrorContext(); + context.setHttpStatus(expectedStatus); + context.setErrorCode(errorCode); + context.setMessage(message); + context.setLocale(locale); + context.setInnerError(innerError); ODataResponse response = - new AtomEntityProvider().writeErrorDocument(expectedStatus, errorCode, message, locale, innerError); + new AtomEntityProvider().writeErrorDocument(context); String errorXml = verifyResponse(response); verifyXml(errorCode, message, locale, innerError, errorXml); } @@ -267,4 +306,23 @@ public class XmlErrorProducerTest extends AbstractXmlProducerTestHelper { assertXpathExists("/a:error/a:innererror", errorXml); } } + + private void verifyDetailsXml(final String errorCode, final String message, + String severity, String target, final String errorXml) throws Exception { + assertXpathExists("/a:error/a:innererror/a:errordetails/a:errordetail", errorXml); + + if (errorCode != null) { + assertXpathEvaluatesTo(errorCode, "/a:error/a:innererror/a:errordetails/a:errordetail/a:code", errorXml); + } + if (message != null) { + assertXpathEvaluatesTo(message, "/a:error/a:innererror/a:errordetails/a:errordetail/a:message", errorXml); + } + if (severity != null) { + assertXpathEvaluatesTo(severity, "/a:error/a:innererror/a:errordetails/a:errordetail/a:severity", errorXml); + } + if (target != null) { + assertXpathEvaluatesTo(target, "/a:error/a:innererror/a:errordetails/a:errordetail/a:target", errorXml); + } + } + }