简体   繁体   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?

I have a SOAP service I need to send requests to (specifically Ivanti Integration Web Service ). 我有一个SOAP服务,我需要将请求发送到(特别是Ivanti Integration Web Service )。

I use Apache CXF 3.2.7 to connect to the service. 我使用Apache CXF 3.2.7连接到该服务。 I generate Java classes from the service's WSDL using wsdl2java . 我使用wsdl2java从服务的WSDL生成Java类。

The WSDL makes no mention of any GUIDs and seems entirely self-sufficient. WSDL没有提及任何GUID,并且看起来完全是自给自足的。 However, there is one field (named Value ) that is untyped, ie an xsd:element without a type attribute, and the server sends responses with values of various types in this field. 但是,有一个未类型化的字段(名为Value ),即没有type属性的xsd:element ,并且服务器在此字段中发送具有各种类型值的响应。 They look like this: 他们看起来像这样:

  •  <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> 

Strings and shorts are fine, but the GUIDs produce this exception on the client: 字符串和短裤都可以,但是GUID在客户端产生此异常:

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

How do I avoid this exception? 如何避免这种异常? I don't actually care about the value of this field, although a solution that achieves type-safe unmarshalling would, of course, be ideal. 尽管可以实现类型安全解组的解决方案当然是理想的,但我实际上并不关心该字段的价值。

What I've tried 我尝试过的

No matter what I do, the exception just doesn't go away. 不管我做什么,例外都不会消失。 In particular, I've tried: 我特别尝试过:

  • adding <jaxb:binding><jaxb:property><jaxb:baseType> to my customized binding XML to make it treat the field as a string—it made the Java property a string but apparently kept unmarshaling data according to the specified types and broke because it coudn't convert a date to a string; <jaxb:binding><jaxb:property><jaxb:baseType>到我的自定义绑定XML中,以使其将字段视为字符串-它使Java属性成为字符串,但显然根据指定的类型保留了对数据的编组并破坏了因为它不能将日期转换为字符串;

  • adding <jaxb:javaType> or <jxc:javaType> with a custom unmarshalling method—this didn't work at all, wsdl2java failed with “compiler was unable to honor this conversion customization. 使用自定义解组方法添加<jaxb:javaType><jxc:javaType> -根本不起作用, wsdl2java失败,原因是“编译器无法wsdl2java此转换自定义。 It is attached to a wrong place, or its inconsistent with other bindings” no matter where I placed the element and no matter what Java type I specified; 不管我放置元素的位置如何,无论我指定的Java类型是什么,它都附在错误的位置,或与其他绑定不一致。

  • manually adding the type definition from one of these sources : 以下 来源 之一手动添加类型定义:

     <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> 

    to the service's WSDL file before invoking wsdl2java on it—after adding an xsd:element in addition to the xsd:simpleType , I finally got wsdl2java to generate a method on ObjectFactory annotated with @XmlElementDecl(namespace = "http://microsoft.com/wsdl/types/", name = "guid") , but this method still wasn't used, plain String was still used wherever my WSDL referred to guid , and the UnmarshalException persisted; 在调用wsdl2java之前, wsdl2java其添加到服务的WSDL文件中-在除了xsd:simpleType之外添加xsd:element之后,我终于得到wsdl2java来在ObjectFactory上生成一个以@XmlElementDecl(namespace = "http://microsoft.com/wsdl/types/", name = "guid") ,但是仍然没有使用此方法,无论我的WSDL指向guid还是在哪里,仍然使用纯String ,并且UnmarshalException仍然存在;

  • even adding an in- Interceptor on the USER_STREAM phase that eats up the entire InputStream into a string, brutally finds all things that look like the GUID xsi:type / xmlns:q2 attributes and replaces them with xsi:type="xsd:string" similar to this answer —but I must have made some mistake, because the exception still didn't go away; 甚至在USER_STREAM阶段添加了一个InterceptorUSER_STREAM整个InputStream吞噬成字符串,然后残酷地找到了所有看起来像GUID xsi:type / xmlns:q2属性的东西,并将它们替换为xsi:type="xsd:string"类似于这个答案,但是我一定犯了一些错误,因为异常仍然没有消失。 here's my code: 这是我的代码:

     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()); } } 

    Then I use this.service to invoke the strongly typed operation methods. 然后,我使用this.service调用强类型的操作方法。 Perhaps the interceptor isn't preserved beyond the local client variable? 也许拦截器没有保留在本地client变量之外?

If I understand correctly (which I'm not at all sure about), this exception means that JAXB doesn't have an unmarshaller registered for the GUID type and it should be resolved if I could somehow get a hold on the JAXB registry and add my own marshaller. 如果我理解正确(我完全不确定),则此异常表示JAXB没有为GUID类型注册解组器,如果可以通过某种方式保留JAXB注册表并添加,则应解决该问题。我自己的编组员。 But after looking at CXF's JavaDocs, I have no idea how, or even if, I could gain access to this registry. 但是,在查看了CXF的JavaDocs之后,我不知道如何,甚至可以访问此注册表。 Some methods sound like I might be able to get a JAXBContext , but I don't see how I could add anything to an already existing JAXBContext instance. 某些方法听起来似乎可以获取JAXBContext ,但是我看不到如何向现有的JAXBContext实例添加任何东西。

If you import the sources generated by wsdl2java from your original WSDL into your source control (and stop generating them on every build), you can add a custom class mapping the simpleType : 如果将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;
}

and add a @XmlSeeAlso(Guid.class) annotation to one of your wsdl2java -generated classes that are already being picked up by JAXB, eg the actual service class. 并将@XmlSeeAlso(Guid.class)注释添加到您的wsdl2java生成的类@XmlSeeAlso(Guid.class)中的一个,例如实际的服务类。 The service class probably already has @XmlSeeAlso({ObjectFactory.class}) , so you can just change that to @XmlSeeAlso({ObjectFactory.class, Guid.class}) . 服务类可能已经具有@XmlSeeAlso({ObjectFactory.class}) ,因此您可以将其更改为@XmlSeeAlso({ObjectFactory.class, Guid.class})

This way, JAXB will successfully unmarshal the GUIDs as Guid instances with plain string contents. 这样,JAXB将成功将GUID解组为具有纯字符串内容的Guid实例。 If you want actual java.util.UUID instances, you may be able to add @XmlJavaTypeAdapter on the @XmlValue field, but I haven't tested this. 如果您需要实际的java.util.UUID实例,则可以在@XmlValue字段上添加@XmlJavaTypeAdapter ,但是我尚未对此进行测试。

(By the way: when you tried adding xsd:element to the WSDL, I think you added a mapping for an XML element named guid , eg <q2:guid xmlns:q2="http://microsoft.com/wsdl/types/">c3aca40a-439d-4af2-b42e-59b1ddcf3d6e</q2:guid> . This isn't what you wanted, so this explains why it didn't help you.) (顺便说一句:当您尝试向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