[英]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
階段添加了一個Interceptor
, USER_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
,我認為您為名為guid
的XML元素添加了映射,例如<q2:guid xmlns:q2="http://microsoft.com/wsdl/types/">c3aca40a-439d-4af2-b42e-59b1ddcf3d6e</q2:guid>
。這不是您想要的,所以這解釋了為什么它對您沒有幫助。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.