繁体   English   中英

如何教Apache CXF JAX-WS客户端使用的JAXB解组无类型属性中的{http://microsoft.com/wsdl/types/}guid值?

[英]How to teach JAXB used by Apache CXF JAX-WS client to unmarshal {http://microsoft.com/wsdl/types/}guid values in an untyped property?

我有一个SOAP服务,我需要将请求发送到(特别是Ivanti Integration Web Service )。

我使用Apache CXF 3.2.7连接到该服务。 我使用wsdl2java从服务的WSDL生成Java类。

WSDL没有提及任何GUID,并且看起来完全是自给自足的。 但是,有一个未类型化的字段(名为Value ),即没有type属性的xsd:element ,并且服务器在此字段中发送具有各种类型值的响应。 他们看起来像这样:

  •  <Value xsi:type="xsd:string">foobar</Value> 
  •  <Value xsi:type="xsd:short">1</Value> 
  •  <Value xsi:type="q2:guid" xmlns:q2="http://microsoft.com/wsdl/types/">c3aca40a-439d-4af2-b42e-59b1ddcf3d6e</Value> 

字符串和短裤都可以,但是GUID在客户端产生此异常:

javax.xml.bind.UnmarshalException: unrecognized type name: {http://microsoft.com/wsdl/types/}guid

如何避免这种异常? 尽管可以实现类型安全解组的解决方案当然是理想的,但我实际上并不关心该字段的价值。

我尝试过的

不管我做什么,例外都不会消失。 我特别尝试过:

  • <jaxb:binding><jaxb:property><jaxb:baseType>到我的自定义绑定XML中,以使其将字段视为字符串-它使Java属性成为字符串,但显然根据指定的类型保留了对数据的编组并破坏了因为它不能将日期转换为字符串;

  • 使用自定义解组方法添加<jaxb:javaType><jxc:javaType> -根本不起作用, wsdl2java失败,原因是“编译器无法wsdl2java此转换自定义。 不管我放置元素的位置如何,无论我指定的Java类型是什么,它都附在错误的位置,或与其他绑定不一致。

  • 以下 来源 之一手动添加类型定义:

     <xs:schema elementFormDefault="qualified" targetNamespace="http://microsoft.com/wsdl/types/" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="guid"> <xs:restriction base="xs:string"> <xs:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"/> </xs:restriction> </xs:simpleType> </xs:schema> 

    在调用wsdl2java之前, wsdl2java其添加到服务的WSDL文件中-在除了xsd:simpleType之外添加xsd:element之后,我终于得到wsdl2java来在ObjectFactory上生成一个以@XmlElementDecl(namespace = "http://microsoft.com/wsdl/types/", name = "guid") ,但是仍然没有使用此方法,无论我的WSDL指向guid还是在哪里,仍然使用纯String ,并且UnmarshalException仍然存在;

  • 甚至在USER_STREAM阶段添加了一个InterceptorUSER_STREAM整个InputStream吞噬成字符串,然后残酷地找到了所有看起来像GUID xsi:type / xmlns:q2属性的东西,并将它们替换为xsi:type="xsd:string"类似于这个答案,但是我一定犯了一些错误,因为异常仍然没有消失。 这是我的代码:

     import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import org.apache.commons.io.IOUtils; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.message.Message; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; public class GuidExpungeInterceptor extends AbstractPhaseInterceptor<Message> { private static class GuidExpungedInputStream extends ByteArrayInputStream { private final InputStream stream; public GuidExpungedInputStream(InputStream stream) throws IOException { super(guidExpungedByteArray(stream)); this.stream = stream; } private static byte[] guidExpungedByteArray(InputStream stream) throws IOException { String content = IOUtils.toString(stream, StandardCharsets.ISO_8859_1); content = content.replaceAll("<Value xsi:type=\\"([A-Za-z_][A-Za-z0-9_.-]*):guid\\" xmlns:\\\\1=\\"http://microsoft.com/wsdl/types/\\">", "<Value xsi:type=\\"xsd:string\\">"); return content.getBytes(StandardCharsets.ISO_8859_1); } @Override public void close() throws IOException { stream.close(); super.close(); } } public GuidExpungeInterceptor() { super(Phase.USER_STREAM); } @Override public void handleMessage(Message message) { if (message == message.getExchange().getInMessage()) { try { InputStream stream = message.getContent(InputStream.class); message.setContent(InputStream.class, new GuidExpungedInputStream(stream)); } catch (IOException e) { throw new Fault(e); } } } } 
     class BlahController { BlahController() { JaxWsProxyFactoryBean proxyFactory = new JaxWsProxyFactoryBean(); proxyFactory.setServiceClass(FRSHEATIntegrationSoap.class); proxyFactory.setAddress(this.properties.getFrsHeatIntegrationUrl()); this.service = (FRSHEATIntegrationSoap) proxyFactory.create(); Client client = ClientProxy.getClient(service); client.getInInterceptors().add(new GuidExpungeInterceptor()); } } 

    然后,我使用this.service调用强类型的操作方法。 也许拦截器没有保留在本地client变量之外?

如果我理解正确(我完全不确定),则此异常表示JAXB没有为GUID类型注册解组器,如果可以通过某种方式保留JAXB注册表并添加,则应解决该问题。我自己的编组员。 但是,在查看了CXF的JavaDocs之后,我不知道如何,甚至可以访问此注册表。 某些方法听起来似乎可以获取JAXBContext ,但是我看不到如何向现有的JAXBContext实例添加任何东西。

如果将wsdl2java生成的源从原始WSDL导入到源代码控件中(并在每次构建时停止生成它们),则可以添加一个映射simpleType的自定义类:

import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;

@XmlType(namespace = "http://microsoft.com/wsdl/types/", name = "guid")
public class Guid {
   @XmlValue
   public String guid;
}

并将@XmlSeeAlso(Guid.class)注释添加到您的wsdl2java生成的类@XmlSeeAlso(Guid.class)中的一个,例如实际的服务类。 服务类可能已经具有@XmlSeeAlso({ObjectFactory.class}) ,因此您可以将其更改为@XmlSeeAlso({ObjectFactory.class, Guid.class})

这样,JAXB将成功将GUID解组为具有纯字符串内容的Guid实例。 如果您需要实际的java.util.UUID实例,则可以在@XmlValue字段上添加@XmlJavaTypeAdapter ,但是我尚未对此进行测试。

(顺便说一句:当您尝试向WSDL中添加xsd:element ,我认为您为名为guidXML元素添加了映射,例如<q2:guid xmlns:q2="http://microsoft.com/wsdl/types/">c3aca40a-439d-4af2-b42e-59b1ddcf3d6e</q2:guid> 。这不是您想要的,所以这解释了为什么它对您没有帮助。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM