Обработчик JAX-WS игнорирует подэлементы ошибки

Я реализую клиент веб-службы, используя JAX-WS через SOAP. Его коды ошибок возвращаются следующим образом:

<?xml version = '1.0' encoding = 'UTF-8'?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
   <env:Header>
      <!-- header stuff goes here -->
   </env:Header>
   <env:Body>
      <env:Fault>
        <abc:fault xmlns:abc="http://example.com/abc">
           <abc:faultcode>12345</abc:faultcode>
           <abc:faultstring>Error message goes here</abc:faultstring>
        </abc:fault>
     </env:Fault>
   </env:Body>
</env:Envelope>

Насколько я знаю, это неправильный способ устранения ошибок SOAP. Подэлементами env:Fault должны быть <faultcode> и <faultstring>, а не другое пространство имен <fault>. К сожалению, у меня нет возможности заставить веб-службу изменить это.

Я надеялся, что смогу проанализировать это сообщение в SOAPHandler и преобразовать его в обычную ошибку, прежде чем передать его остальной части моего кода, однако, когда я зарегистрировал сообщение в более раннем обработчике, я увидел, что элемент Fault полностью пустой. <abc:fault> пропало!

Я использую JAX-WS в WebSphere 7 и пытался установить для параметра "jaxws.payload.highFidelity" значение true в свойствах моей системы. Любые подсказки о том, как добраться до исходного сообщения?

Если оставить это в покое, возникнет WebServiceException с NullPointerException, поскольку JAX-WS не сможет найти код ошибки.


person summer    schedule 25.01.2013    source источник


Ответы (2)


Так я нашел ответ на свой вопрос. WebSphere 7 использует Axis2. MessageContext Axis2 предоставляет свойство под названием «TRANSPORT_IN», которое содержит ByteArrayInputStream. TRANSPORT_IN, как следует из названия, содержит точное полученное сообщение SOAP.

Я проанализировал исходное сообщение SOAP в своем методе Handler#handleFault, используя SAXHandler для получения сообщения abc:fault. Затем я записал abc:fault > код ошибки и строку ошибки в код ошибки и строку ошибки soapenv:Fault. Затем мое приложение обрабатывает исключение SOAPFaultException, как если бы оно было обычным.

Я все еще очень открыт для любых лучших ответов, так как это похоже на окольный способ сделать это.

Код обработчика:

public boolean handleFault(SOAPMessageContext context) {
    SOAPMessage m = context.getMessage();
    if(m != null) {
        SOAPBody body = m.getSOAPBody();
        SOAPFault fault = body.getFault();
        setAbcFault(fault, context);
    }
}

private void setAbcFault(SOAPFault fault, MessageContext context) {
    ByteArrayInputStream bis = (ByteArrayInputStream)context.get("TRANSPORT_IN");
    // do sax parsing on the input stream
    fault.setFaultCode(abcFaultCodeQName);
    fault.setFaultString(abcFaultString);
}
person summer    schedule 27.01.2013
comment
В конце дня я написал XSLT и пользовательский WSDL/XSD, которые преобразовывали сообщение в надлежащую ошибку SOAP в устройстве безопасности, прежде чем оно попало в WAS. Внутри WAS я использовал пользовательский WSDL/XSD и нормально обработал исключение. - person summer; 02.08.2014

Если вы используете JAX-WS, вы можете использовать ошибки SOAP. или что, вам нужно исключение с аннотацией @WebFault. Вы можете найти хороший пример в Использование ошибок и исключений SOAP в Java Веб-службы JAX-WS — Эбен Хьюитт о Java.

См. ответ для возврата null или исключения и Как вызвать пользовательскую ошибку в веб-службе JAX-WS?

Пример:

@WebService
public class CalculatorWS {

    public String factorial(int n) throws FactorialException {
        if (n < 0) {
            throw new FactorialException("Negative number!",     // faultstring
                                         "The number n = " + n); // detail
        }
        return BigIntegerMath.factorial(n).toString();
    }

}

С участием:

public class FactorialException extends Exception {

    String detail;

    public FactorialException(String message, String detail) {
        super(message);
        this.detail = detail;
    }

    public String getFaultInfo() {
        return detail;
    }

}

Если запрос:

<soapenv:Envelope ... >
   <soapenv:Header/>
   <soapenv:Body>
      <test:factorial>
         <arg0>-1</arg0>
      </test:factorial>
   </soapenv:Body>
</soapenv:Envelope>

Ответ:

<soapenv:Envelope ... >
   <soapenv:Body>
      <soapenv:Fault>
         <faultcode>soapenv:Server</faultcode>
         <faultstring>Negative number!</faultstring>
         <detail>
            <ns2:FactorialExceptionBean xmlns:ns2="http://...">
                The number n = -1
            </ns2:FactorialExceptionBean>
         </detail>
      </soapenv:Fault>
   </soapenv:Body>
</soapenv:Envelope>

(Проверено в Websphere 7)

person Paul Vargas    schedule 26.01.2013
comment
Как я уже упоминал, я не контролирую ответное сообщение. Я запускаю клиент, а не сервер. Если бы их пользовательская ошибка была в элементе подробностей, это не было бы проблемой. Их ошибка имеет структуру env:Fault › abc:fault. Я не могу получить abc:fault, потому что JAX-WS полностью удаляет его из SOAPHandler. - person summer; 27.01.2013