Hello.
Thank you, Mark, for your reply.
I'm giving more details about my service as you ask:
1. I repeat: the contract (XSD) for my service was provided from my customer. So I've got the contract-first architecture.
2. In all response SOAP-messages there is a block in body:
HTML Code:
<complexType name="ErrorInformationType">
<sequence>
<element name="errorCode" type="string" nillable="true"/>
<element name="errorDescription" type="string"/>
<element name="errorSeverity" type="tns:ErrorSeverityType"/>
<element name="errorCategory" type="tns:ErrorCategoryType"/>
</sequence>
</complexType>
3. So, my customer doesn't want to receive exceptions from me - he wants have some error code and user-friendly description of that. I think, he shows this info in his web-client and covers a message with css by
errorSeverity and
errorCategory
4. The biggest part of my exceptions occur in DB layer by calling of stored procedures. So, I must parse the
SQLException and take a bite of error code and error-message. At last I must build the regular SOAP-response and add to that the
ErrorInformation tag as described previously
I know about exception-handling with SOAP-Foult and know about
EndpointExceptionResolver in Srping-WS project. And at first I try to implement required solution with
CustomEndpointExceptionResolver. But in request and response messages in messageContext are
AxiomSoapMessage type and it is difficult to parse them and build messages with axiom API. And I found this solution not smart.
By using the solution with error-channel I implement the ErrorUnwrapper Transformer:
Code:
public class ErrorUnwrapper extends AbstractTransformer {
@Override
protected Object doTransform(Message<?> errorMessage) throws Exception {
MessagingException exception = (MessagingException) errorMessage.getPayload();
Message<?> failedMessage = exception.getFailedMessage();
Response response = (Response) failedMessage.getHeaders().get("response");
response.getHeaderData().setErrorInformation(buildErrorInformation(exception));
return MessageBuilder.withPayload(response).copyHeaders(failedMessage.getHeaders())
.setReplyChannel((MessageChannel) errorMessage.getHeaders().getReplyChannel())
.build();
}
private ErrorInformationType buildErrorInformation(MessagingException exception) {
ErrorInformationType errorInformation = new ErrorInformationType();
SQLException sqlException = findSQLException(exception);
if (sqlException != null) {
errorInformation.setErrorDescription(sqlException.getMessage());
errorInformation.setErrorCode("" + sqlException.getErrorCode());
errorInformation.setErrorCategory(ErrorCategory.BUSI);
errorInformation.setErrorSeverity(ErrorSeverity.E);
} else {
errorInformation.setErrorDescription(ExceptionUtils.getFullStackTrace(exception));
errorInformation.setErrorCode("-1");
errorInformation.setErrorCategory(ErrorCategory.TECH);
errorInformation.setErrorSeverity(ErrorSeverity.E);
}
return errorInformation;
}
private SQLException findSQLException(Exception e) {
List<Exception> causes = new ArrayList<Exception>();
for (Exception cause = e; cause != null; cause = getCause(cause)) {
causes.add(cause);
}
for (int i = causes.size() - 1; i >= 0; i--) {
Exception cause = causes.get(i);
if (cause instanceof SQLException) {
return (SQLException) cause;
}
}
return null;
}
private Exception getCause(Exception exception) {
Throwable cause = exception.getCause();
return cause == exception || !(cause instanceof Exception) ? null : (Exception) cause;
}
}
So, I think, it is more flexible solution to work with simple objects than parse XML with specific APIs.
Thank you