19

ゴール

私はかなり古い (しかし悲しいことに変更不可能な) インターフェイス用の Web サービスを実装しています。サービスを呼び出しているクライアントが SOAP 応答で特定の名前空間を期待しているという問題があり、一致するように変更するのが困難です。

こんにちは世界の例を考えると、私はこれが欲しいです:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:helloResponse xmlns:ns2="http://test/">
         <return>Hello Catchwa!</return>
      </ns2:helloResponse>
   </S:Body>
</S:Envelope>

次のようになります。

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <customns:helloResponse xmlns:customns="http://test/">
         <return>Hello Catchwa!</return>
      </customns:helloResponse>
   </S:Body>
</S:Envelope>

ここでやろうとしていることに似たものを見つけましたが、同様のコードを適切に実行するのに問題があります。(私は Metro を使い続けたいので、cxf や axis に変更する必要はありません)


実行

私の実装は次のようJAXBContextFactoryになります。JAXBRIContext

import com.sun.xml.bind.api.JAXBRIContext;
import com.sun.xml.bind.api.TypeReference;
import com.sun.xml.ws.api.model.SEIModel;
import com.sun.xml.ws.developer.JAXBContextFactory;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;

public class HelloJaxbContext implements JAXBContextFactory
{
  @Override
  public JAXBRIContext createJAXBContext(SEIModel seim, List<Class> classesToBind, List<TypeReference> typeReferences) throws JAXBException {
    List<Class> classList = new ArrayList<Class>();
    classList.addAll(classesToBind);

    List<TypeReference> refList = new ArrayList<TypeReference>();
    for (TypeReference tr : typeReferences) {
        refList.add(new TypeReference(new QName(tr.tagName.getNamespaceURI(), tr.tagName.getLocalPart(), "customns"), tr.type, tr.annotations));
    }
    return JAXBRIContext.newInstance(classList.toArray(new Class[classList.size()]), refList, null, seim.getTargetNamespace(), false, null);
  }  
}

Web サービスのテスト コードは次のとおりです。

import com.sun.xml.ws.developer.UsesJAXBContext;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.WebParam;

@WebService(serviceName = "Hello")
@UsesJAXBContext(value = HelloJaxbContext.class)
public class Hello
{
  @WebMethod(operationName = "hello")
  public String hello(@WebParam(name = "name") String txt)
  {
    return "Hello " + txt + "!";
  }
}

問題

jaxws-rt 2.2.7 (Maven から) を使用する Tomcat 7.0.32 および Glassfish 3.1.2 では、上記のコードは Web サービスの出力に影響しません (名前空間のプレフィックスはまだ「ns2」です)。

4

3 に答える 3

27

古いサービスの WSDL から開始し、 を使用してさまざまな JAXB アノテーション付き要求および応答ラッパー クラスをすべて生成したwsimport場合、生成されたパッケージには次のpackage-info.javaようなものがあります。

@javax.xml.bind.annotation.XmlSchema(namespace = "http://test/")
package com.example.test;

JAXB は、アノテーションのプレフィックス マッピングを提案するメカニズムを提供するため、読み取りに@XmlSchema変更を加えることができます。package-info.java

@javax.xml.bind.annotation.XmlSchema(namespace = "http://test/",
   xmlns = { 
      @javax.xml.bind.annotation.XmlNs(prefix = "customns", 
         namespaceURI="http://test/")
   }
)
package com.example.test;

生成されたメッセージに違いがあるかどうかを確認します。これには、純粋な JAXB 仕様である (つまり、RI 固有のカスタム コンテキスト ファクトリに依存しない) という利点もあります。

再実行する必要がある場合は、オプションを に渡すことでwsimport、変更したものを上書きしないようにすることができます(これにより、 を生成するのではなく、必要なすべての設定をクラス レベルのアノテーションに配置するように指示されます)。これを正確に行う方法は、実行方法によって異なります。package-info-npaxjcpackage-info.javanamespacewsimport

コマンドライン:

wsimport -B-npa ....

蟻:

<wsimport wsdl="..." destdir="..." .... >
  <xjcarg value="-npa" />
</wsimport>

メイヴン:

<plugin>
  <groupId>org.jvnet.jax-ws-commons</groupId>
  <artifactId>jaxws-maven-plugin</artifactId>
  <version>2.2</version>
  <executions>
    <execution>
      <goals>
        <goal>wsimport</goal>
      </goals>
      <configuration>
        <xjcArgs>
          <xjcArg>-npa</xjcArg>
        </xjcArgs>
      </configuration>
    </execution>
  </executions>
</plugin>
于 2012-10-18T09:56:51.160 に答える
4

達成しようとしていることを達成するための推奨/標準的な方法は、 SOAPMessageハンドラーを使用することです。これらは、 Chain of Responsibilityパターンを実装するために使用されるため、Java Webアプリケーションフィルター(理論的にはここでも機能する可能性があります)に類似しています。たとえば、あなたの場合、あなたはこれを持つことができます:

import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;


public class SOAPBodyHandler implements SOAPHandler<SOAPMessageContext> {

static final String DESIRED_NS_PREFIX = "customns";
static final String DESIRED_NS_URI = "http://test/";
static final String UNWANTED_NS_PREFIX = "ns";

@Override
public Set<QName> getHeaders() {
   //do nothing
   return null;
}

@Override
public boolean handleMessage(SOAPMessageContext context) {
    if ((boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) { //Check here that the message being intercepted is an outbound message from your service, otherwise ignore.
        try {
            SOAPEnvelope msg = context.getMessage().getSOAPPart().getEnvelope(); //get the SOAP Message envelope
            SOAPBody body = msg.getBody();
            body.removeNamespaceDeclaration(UNWANTED_NS_PREFIX);
            body.addNamespaceDeclaration(DESIRED_NS_PREFIX, DESIRED_NS_URI); 
        } catch (SOAPException ex) {
            Logger.getLogger(SOAPBodyHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    return true; //indicates to the context to proceed with (normal)message processing
}

@Override
public boolean handleFault(SOAPMessageContext context) {
      //do nothing
   return null;
}

@Override
public void close(MessageContext context) {
      //do nothing

}

}

Service Implementation Beanクラス宣言で、次のように追加します。

  @HandlerChain(file = "handler-chain.xml")

上記の注釈は、ハンドラーが実際にキックインできるようにする構成ファイルへの参照です。設定ファイルは次のようになります

  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
     <javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee" 
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <javaee:handler-chain>
           <javaee:handler>
              <javaee:handler-class>your.handler.FQN.here</javaee:handler-class>
           </javaee:handler>
        </javaee:handler-chain>
     </javaee:handler-chains> 

家でこれを試してみてください。この特定のコードはテストされていません

于 2012-10-18T05:49:59.907 に答える
0

リファレンス実装では、最終的に機能させるためにこれを行いました。Metro を使用して JAXB クラスをマーシャリングするときに schemaLocation が無視されるを参照してください。

于 2012-10-18T14:58:17.043 に答える