自定义SOAP响应的JAX-WS前缀

Cat*_*hwa 18 java soap jax-ws jaxb

目标

我正在为一个相当古老(但可悲的是不可改变的)界面实现一个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>
Run Code Online (Sandbox Code Playgroud)

看起来像这样:

<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>
Run Code Online (Sandbox Code Playgroud)

我找到了类似于我在这里尝试的东西,但是我无法获得类似的代码来正确执行.(我想坚持使用Metro,而不必更改为cxf或轴)


执行

我的实现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);
  }  
}
Run Code Online (Sandbox Code Playgroud)

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 + "!";
  }
}
Run Code Online (Sandbox Code Playgroud)

问题

在使用jaxws-rt 2.2.7(来自Maven)的Tomcat 7.0.32和Glassfish 3.1.2中,上面的代码不会影响我的Web服务输出(名称空间前缀仍然是"ns2").

Ian*_*rts 24

如果您使用旧服务的WSDL开始,所有产生的各种JAXB注释的请求和响应的包装类wsimport,然后在生成的包,你应该找到一个package-info.java

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

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;
Run Code Online (Sandbox Code Playgroud)

并查看是否对生成的消息产生任何影响.这也具有纯JAXB规范的优点(即不依赖于RI特定的自定义上下文工厂).

如果你需要重新运行wsimport,可以package-info通过传递-npa选项来阻止它覆盖你修改的xjc(这告诉它不要生成一个package-info.java,而是将所有必要的namespace设置放在类级别的注释上).具体如何做到这一点取决于你的运行方式wsimport.

命令行:

wsimport -B-npa ....
Run Code Online (Sandbox Code Playgroud)

蚂蚁:

<wsimport wsdl="..." destdir="..." .... >
  <xjcarg value="-npa" />
</wsimport>
Run Code Online (Sandbox Code Playgroud)

Maven的:

<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>
Run Code Online (Sandbox Code Playgroud)