import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.List; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.soap.DetailEntry; import javax.xml.soap.Node; import javax.xml.soap.SOAPException; import javax.xml.ws.Binding; import javax.xml.ws.BindingProvider; import javax.xml.ws.handler.Handler; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; public class JaxWsExceptionCatcher { private static final class MyExceptionHandler implements InvocationHandler { private final T port; private MyExceptionHandler(T port) { this.port = port; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { return method.invoke(port, args); } catch (InvocationTargetException e) { Throwable bre = e.getTargetException().getCause(); if (bre != null && bre instanceof MyRuntimeException) { throw bre.getCause(); } throw e; } } } private static class MyRuntimeException extends RuntimeException { private static final long serialVersionUID = -2143724572440079147L; private MyRuntimeException(MyException cause) { super(cause); } } private static class MyFaultHandler implements SOAPHandler { private final String namespace; public MyFaultHandler(String namespace) { this.namespace = namespace; } @Override public boolean handleMessage(SOAPMessageContext context) { return true; } @Override public boolean handleFault(SOAPMessageContext context) { try { DetailEntry detailEntry = (DetailEntry) context.getMessage() .getSOAPBody().getFault().getDetail() .getDetailEntries().next(); if (detailEntry.getNamespaceURI().equals(namespace) && detailEntry.getLocalName().equals("MyException")) { String code = ((Node) detailEntry.getChildElements( new QName("code")).next()).getTextContent(); String message = ((Node) detailEntry.getChildElements( new QName("message")).next()).getTextContent(); if (code != null && message != null) { throw new MyRuntimeException(new MyException(code, message)); } } return true; } catch (NullPointerException e) { // Soap fault is not in the format we expected return true; } catch (SOAPException e) { return true; } } @Override public void close(MessageContext context) { } @Override public Set getHeaders() { return null; } } public final static T catchOn(final T port, String namespace) { Binding binding = ((BindingProvider) port).getBinding(); List handlerChain = binding.getHandlerChain(); handlerChain.add(new MyFaultHandler(namespace)); binding.setHandlerChain(handlerChain); Object pi = Proxy.newProxyInstance(port.getClass().getClassLoader(), port.getClass().getInterfaces(), new MyExceptionHandler(port)); return (T) pi; } }