An HTML page is usually a server error yes. Probably a static service page (like 404 or 5xx). It could even be an error in your request that should be returned as a SOAPFault, but is not implemented as such by the specific server.
Sometimes the server does communicate a valid SOAP (Fault) message, but the content type header is just wrong. In that case you're better off rewriting the Content-Type
from the response with a proxy server. See for references on this subject:
So, what can you do to view the HTML content?
With JAX-WS you can enable all HTTP web service traffic to be logged to System.out
with the following vm options:
-Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=TRUE
-Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=TRUE
-Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=TRUE
-Dcom.sun.xml.internal.ws.transport.http.HttpAdapter.dump=TRUE
-Dcom.sun.xml.internal.ws.transport.http.HttpAdapter.dumpTreshold=999999
See for references:
Now, this will dump all http requests and responses, but you might only be interested in the ones where you don't get soap/xml.
So, what else can you do?
You could set these options programmatically and re-send the request when you catch the UnsupportedMediaException
. But in the time this takes the error might have disappeared. Note that these properties are cached, so setting them needs to go through com.sun.xml.ws.transport.http.client.HttpTransportPipe#setDump(Boolean)
If you're willing to switch to the JAX-WS runtime, you could also create your own com.sun.xml.ws.api.pipe.TransportTubeFactory
since jaxws-rt
can load custom instances of this factory. I have successfully created my own TransportTubeFactory that uses a custom com.sun.xml.ws.transport.http.client.HttpTransportPipe
(by extending it and overriding processRequest
) that reads the http response from the com.sun.xml.ws.api.pipe.Codec
upon catching the UnsupportedMediaException. By wrapping the Codec you can store the input stream on the decode
method call.
This runtime is nearly identical to the internal runtime, and should be fully compatible.
This may also work with the internal classes from the Java runtime, but since those are located in RT.jar
it's difficult to depend on it and build your project. So i would advice switching to the external JAX-WS runtime.
What you then do with the input stream is up to you (which is the body of the HTTP response at the moment of catching the UnsupportedMediaException).
Note that you can also rewrite most* content type headers in code with this codec wrapper.
See for reference how to add your own implementation of this factory via META-INF/services
here:
In short:
- Create a file in META-INF/services called
com.sun.xml.ws.api.pipe.TransportTubeFactory
- The contents of this file should be a single line with the full class name of your custom factory, for example
my.soap.transport.MyTransportTubeFactory
Note; if you're using the classes from the Java runtime instead of jaxws-rt, use com.sun.xml.internal.ws
as the package for everything in this post that references com.sun.xml.ws
.
*Note: newer versions of this runtime (jaxws-rt-2.3.x or jre 8+ internal) throw a different exception on text/html
responses. Sadly before calling Codec.decode. So in that case you would have to copy more code into your custom HttpTransportPipe. text/plain
currently still works though.
Some snippets of my code:
public class TransportTubeFactoryImpl extends TransportTubeFactory {
@Override
public Tube doCreate(ClientTubeAssemblerContext context) {
String scheme = context.getAddress().getURI().getScheme();
if (scheme != null) {
if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
CodecWrapper codec = new CodecWrapper(context.getCodec());
return new HttpTransportPipeImpl(codec, context.getBinding());
}
}
throw new WebServiceException("Unsupported endpoint address: " + context.getAddress());
}
}
public class CodecWrapper implements Codec {
private Codec wrapped;
public CodecWrapper(Codec wrapped) {
this.wrapped = wrapped;
}
@Override
public void decode(InputStream in, String contentType, Packet response) throws IOException {
copyInputStream(in); // todo: implement this
wrapped.decode(in, contentType, response);
}
}
public class HttpTransportPipeImpl extends HttpTransportPipe {
private CodecWrapper codec;
public HttpTransportPipeImpl(CodecWrapper codec, WSBinding binding) {
super(codec, binding);
this.codec = codec;
}
@Override
public NextAction processRequest(Packet request) {
try {
return super.processRequest(request);
} catch (UnsupportedMediaException ex) {
// todo: here you can access the stored data from the codec wrapper
}
}
}
I have also created a complete working demonstration of this principle on my github: https://github.com/s-lindenau/SoapContentTypeDemo
If you still have the option to switch to a completely different client library, you could also check Apache CXF: