JAXWSを使用して、構築しているJavaアプリケーションのWebServiceクライアントを生成しています。
JAXWSがSOAPプロトコルで使用するXMLを構築すると、次の名前空間プレフィックスが生成されます。
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body ...>
<!-- body goes here -->
</env:Body>
</env:Envelope>
私の問題は、クライアントが接続しているサーバーを管理するカウンターパート(大規模な送金会社)がWebService呼び出しの受け入れを拒否することです(理由を聞かないでください)XMLNS(XML名前空間プレフィックスがsoapenv
)でない限り。このような:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body ...>
<!-- body goes here -->
</soapenv:Body>
</soapenv:Envelope>
だから私の質問は:
JAXWS(または他のJava WSクライアントテクノロジー)に、soapenv
の代わりにenv
をXMLNS
プレフィックスとして使用してクライアントを生成するように命令する方法はありますか?この情報を設定するためのAPI呼び出し?
ありがとう!
多分それはあなたのために遅れて、これがうまくいくかどうかはわかりませんが、あなたは試すことができます。
まず、SoapHandlerを実装する必要があり、handleMessage
メソッドでSOAPMessage
を変更できます。そのプレフィックスを直接変更できるかどうかはわかりませんが、次のことを試すことができます。
public class MySoapHandler implements SOAPHandler<SOAPMessageContext>
{
@Override
public boolean handleMessage(SOAPMessageContext soapMessageContext)
{
try
{
SOAPMessage message = soapMessageContext.getMessage();
// I haven't tested this
message.getSOAPHeader().setPrefix("soapenv");
soapMessageContext.setMessage(message);
}
catch (SOAPException e)
{
// Handle exception
}
return true;
}
...
}
次に、HandlerResolver
を作成する必要があります。
public class MyHandlerResolver implements HandlerResolver
{
@Override
public List<Handler> getHandlerChain(PortInfo portInfo)
{
List<Handler> handlerChain = Lists.newArrayList();
Handler soapHandler = new MySoapHandler();
String bindingID = portInfo.getBindingID();
if (bindingID.equals("http://schemas.xmlsoap.org/wsdl/soap/http"))
{
handlerChain.add(soapHandler);
}
else if (bindingID.equals("http://Java.Sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/"))
{
handlerChain.add(soapHandler);
}
return handlerChain;
}
}
そして最後に、HandlerResolver
をクライアントサービスに追加する必要があります。
Service service = Service.create(wsdlLoc, serviceName);
service.setHandlerResolver(new MyHandlerResolver());
この投稿は、元のポスターには遅すぎる可能性がありますが、これに遭遇する可能性のある他の人を助けることを目的としています。私はこの数日でこの問題を解決しなければなりませんでした。特に、サービスプロバイダーは名前空間プレフィックスが非常に特定のパターンに準拠する必要があるため、SOAPエンベロープで使用されるプレフィックスを変更する必要がありました。このパターンに準拠するには、名前空間プレフィックスを変更する必要がありました。エンベロープ、ヘッダーと本体、および本体要素(JAX-WSによって入力された標準要素から)。これは、私が使用したソリューションの概要です。
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import Java.util.HashSet;
import Java.util.Iterator;
import Java.util.Set;
public class MyMessageNamespaceMapper implements SOAPHandler<SOAPMessageContext> {
@Override
public Set<QName> getHeaders() {
return null;
}
@Override
public boolean handleMessage(SOAPMessageContext context) {
final Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// only process outbound messages
if (outbound) {
try {
final SOAPMessage soapMessage = context.getMessage();
final SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
final SOAPHeader soapHeader = soapMessage.getSOAPHeader();
final SOAPBody soapBody = soapMessage.getSOAPBody();
// STEP 1: add new prefix/namespace entries
soapEnvelope.addNamespaceDeclaration("S1", "http://schemas.xmlsoap.org/soap/envelope/");
soapEnvelope.addNamespaceDeclaration("FOO-1", "http://foo1.bar.com/ns");
// STEP 2: set desired namespace prefixes
// set desired namespace prefix for the envelope, header and body
soapEnvelope.setPrefix("S1");
soapHeader.setPrefix("S1");
soapBody.setPrefix("S1");
addDesiredBodyNamespaceEntries(soapBody.getChildElements());
// STEP 3: remove prefix/namespace entries entries added by JAX-WS
soapEnvelope.removeNamespaceDeclaration("S");
soapEnvelope.removeNamespaceDeclaration("SOAP-ENV");
removeUndesiredBodyNamespaceEntries(soapBody.getChildElements());
// IMPORTANT! "Save" the changes
soapMessage.saveChanges();
}
catch (SOAPException e) {
// handle the error
}
}
return true;
}
private void addDesiredBodyNamespaceEntries(Iterator childElements) {
while (childElements.hasNext()) {
final Object childElementNode = childElements.next();
if (childElementNode instanceof SOAPElement) {
SOAPElement soapElement = (SOAPElement) childElementNode;
// set desired namespace body element prefix
soapElement.setPrefix("FOO-1");
// recursively set desired namespace prefix entries in child elements
addDesiredBodyNamespaceEntries(soapElement.getChildElements());
}
}
}
private void removeUndesiredBodyNamespaceEntries(Iterator childElements) {
while (childElements.hasNext()) {
final Object childElementNode = childElements.next();
if (childElementNode instanceof SOAPElement) {
SOAPElement soapElement = (SOAPElement) childElementNode;
// we remove any prefix/namespace entries added by JAX-WS in the body element that is not the one we want
for (String prefix : getNamespacePrefixList(soapElement.getNamespacePrefixes())) {
if (prefix != null && ! "FOO-1".equals(prefix)) {
soapElement.removeNamespaceDeclaration(prefix);
}
}
// recursively remove prefix/namespace entries in child elements
removeUndesiredBodyNamespaceEntries(soapElement.getChildElements());
}
}
}
private Set<String> getNamespacePrefixList(Iterator namespacePrefixIter) {
Set<String> namespacePrefixesSet = new HashSet<>();
while (namespacePrefixIter.hasNext()) {
namespacePrefixesSet.add((String) namespacePrefixIter.next());
}
return namespacePrefixesSet;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
@Override
public void close(MessageContext context) {
}
}
上記のハンドラーリゾルバーをサービスクラスのインスタンス(JAX-WS/wsimportによって生成される)に設定すると、次のようになります。
yourWebServiceClient.setHandlerResolver(new HandlerResolver() {
@Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
return Arrays.asList(new MyMessageNamespaceMapper());
}
});