[英]How make JAXB generate XML correctly?
我正在尝试使用在soap请求中使用两个名称空间的Web服务,但是它不接受任何前缀。 我正在使用cxf生成客户端和数据绑定。 当使用JAXB作为默认数据绑定时,这是发送到Web服务的服务器的消息:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<nfeCabecMsg xmlns:ns2="http://www.portalfiscal.inf.br/nfe"
xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2">
<cUF>31</cUF>
<versaoDados>2.00</versaoDados>
</nfeCabecMsg>
</soap:Header>
<soap:Body>
<nfeDadosMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2"
xmlns:ns2="http://www.portalfiscal.inf.br/nfe">
<ns2:consStatServ versao="2.00">
<ns2:tpAmb>2</ns2:tpAmb>
<ns2:cUF>31</ns2:cUF>
<ns2:xServ>STATUS</ns2:xServ>
</ns2:consStatServ>
</nfeDadosMsg>
</soap:Body>
</soap:Envelope>
但这不是服务器期望的格式。 使用XmlBean作为默认的数据绑定,我可以正确生成消息(如服务器期望的那样):
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<nfeCabecMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2">
<cUF>31</cUF>
<versaoDados>2.00</versaoDados>
</nfeCabecMsg>
</soap:Header>
<soap:Body>
<nfeDadosMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2">
<consStatServ xmlns="http://www.portalfiscal.inf.br/nfe" versao="2.00">
<tpAmb>2</tpAmb>
<cUF>31</cUF>
<xServ>STATUS</xServ>
</consStatServ>
</nfeDadosMsg>
</soap:Body>
</soap:Envelope>
但是,我真的很喜欢使用XmlBeans,因为我的软件的另一个重要部分是使用JAXB开发的,所以可能需要将其更改为XmlBeans。 在我看到XmlBeans的最新版本是在2012年之后,我不确定将来是否会支持XmlBeans。 有没有一种方法可以使用JAXB正确生成消息?
更新
这是Web服务的wsdl:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:tns="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
targetNamespace="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified"
targetNamespace="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2">
<s:element name="nfeDadosMsg">
<s:complexType mixed="true">
<s:sequence>
<s:any/>
</s:sequence>
</s:complexType>
</s:element>
<s:element name="nfeStatusServicoNF2Result">
<s:complexType mixed="true">
<s:sequence>
<s:any/>
</s:sequence>
</s:complexType>
</s:element>
<s:element name="nfeCabecMsg" type="tns:nfeCabecMsg"/>
<s:complexType name="nfeCabecMsg">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="cUF" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="versaoDados" type="s:string"/>
</s:sequence>
<s:anyAttribute/>
</s:complexType>
</s:schema>
</wsdl:types>
<wsdl:message name="nfeStatusServicoNF2Soap12In">
<wsdl:part name="nfeDadosMsg" element="tns:nfeDadosMsg"/>
</wsdl:message>
<wsdl:message name="nfeStatusServicoNF2Soap12Out">
<wsdl:part name="nfeStatusServicoNF2Result" element="tns:nfeStatusServicoNF2Result"/>
</wsdl:message>
<wsdl:message name="nfeStatusServicoNF2nfeCabecMsg">
<wsdl:part name="nfeCabecMsg" element="tns:nfeCabecMsg"/>
</wsdl:message>
<wsdl:portType name="NfeStatusServico2Soap12">
<wsdl:operation name="nfeStatusServicoNF2">
<wsdl:input message="tns:nfeStatusServicoNF2Soap12In"/>
<wsdl:output message="tns:nfeStatusServicoNF2Soap12Out"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="NfeStatusServico2Soap12" type="tns:NfeStatusServico2Soap12">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="nfeStatusServicoNF2">
<soap12:operation soapAction="http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico2/nfeStatusServicoNF2"
style="document"/>
<wsdl:input>
<soap12:body use="literal"/>
<soap12:header message="tns:nfeStatusServicoNF2nfeCabecMsg" part="nfeCabecMsg" use="literal"/>
</wsdl:input>
<wsdl:output>
<soap12:body use="literal"/>
<soap12:header message="tns:nfeStatusServicoNF2nfeCabecMsg" part="nfeCabecMsg" use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="NfeStatusServico2">
<wsdl:port name="NfeStatusServico2Soap12" binding="tns:NfeStatusServico2Soap12">
<soap12:address location="https://nfe.sefazvirtual.rs.gov.br/ws/NfeStatusServico/NfeStatusServico2.asmx"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
这些是用于创建consStatServ标记的最相关的架构:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.portalfiscal.inf.br/nfe" xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.portalfiscal.inf.br/nfe" elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:include schemaLocation="leiauteConsStatServ_v2.00.xsd"/>
<xs:element name="consStatServ" type="TConsStatServ">
<xs:annotation>
<xs:documentation>Schema XML de validação do Pedido de Consulta do Status do Serviço</xs:documentation>
</xs:annotation>
</xs:element>
</xs:schema>
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.portalfiscal.inf.br/nfe" xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.portalfiscal.inf.br/nfe" elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:include schemaLocation="tiposBasico_v1.03.xsd"/>
<xs:complexType name="TConsStatServ">
<xs:annotation>
<xs:documentation>Tipo Pedido de Consulta do Status do Serviço</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="tpAmb" type="TAmb">
<xs:annotation>
<xs:documentation>Identificação do Ambiente:
1 - Produção
2 - Homologação
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="cUF" type="TCodUfIBGE">
<xs:annotation>
<xs:documentation>Sigla da UF consultada</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="xServ">
<xs:annotation>
<xs:documentation>Serviço Solicitado</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="TServ">
<xs:enumeration value="STATUS"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
<xs:attribute name="versao" type="TVerConsStatServ" use="required"/>
</xs:complexType>
<xs:complexType name="TRetConsStatServ">
<xs:annotation>
<xs:documentation>Tipo Resultado da Consulta do Status do Serviço</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="tpAmb" type="TAmb">
<xs:annotation>
<xs:documentation>Identificação do Ambiente:
1 - Produção
2 - Homologação
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="verAplic" type="TVerAplic">
<xs:annotation>
<xs:documentation>Versão do Aplicativo que processou a NF-e</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="cStat" type="TStat">
<xs:annotation>
<xs:documentation>Código do status da mensagem enviada.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="xMotivo" type="TMotivo">
<xs:annotation>
<xs:documentation>Descrição literal do status do serviço solicitado.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="cUF" type="TCodUfIBGE">
<xs:annotation>
<xs:documentation>Código da UF responsável pelo serviço</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="dhRecbto" type="xs:dateTime">
<xs:annotation>
<xs:documentation>AAAA-MM-DDTHH:MM:SS</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="tMed" type="TMed" minOccurs="0">
<xs:annotation>
<xs:documentation>Tempo médio de resposta do serviço (em segundos) dos últimos 5 minutos
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="dhRetorno" type="xs:dateTime" minOccurs="0">
<xs:annotation>
<xs:documentation>AAAA-MM-DDTHH:MM:SSDeve ser preenchida com data e hora previstas para o retorno
dos serviços prestados.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="xObs" type="TMotivo" minOccurs="0">
<xs:annotation>
<xs:documentation>Campo observação utilizado para incluir informações ao contribuinte
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
<xs:attribute name="versao" type="TVerConsStatServ" use="required"/>
</xs:complexType>
<xs:simpleType name="TVerConsStatServ">
<xs:annotation>
<xs:documentation>Tipo versão do leiuate da Consulta Status do Serviço 2.00</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:token">
<xs:pattern value="2\.00"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
您可能想在生成的类的元素上使用http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/XmlElement.html注释。 它具有您会感兴趣的名称空间参数。我们之前遇到过类似的问题,并且能够使其与那些手动更新一起使用。
我终于解决了问题。 由于这是一个第三方Web服务,因此我唯一的选择是编辑JAXB生成的类。 我要做的第一件事是从package-info.java文件中删除名称空间属性。 然后我在ObjectFactory类中做了同样的事情,这里我只是从以下更改了QName构造函数:
QName(String namespaceURI,String localPart)
至
QName(String localPart)
不幸的是,这些修改并没有删除前缀,因此我实现了自己的CXF拦截器 :
public class NamespacePrefixInterceptor extends AbstractPhaseInterceptor<Message> {
public NamespacePrefixInterceptor() {
super(Phase.PRE_STREAM);
addBefore(SoapPreProtocolOutInterceptor.class.getName());
}
@Override
public void handleMessage(Message message) throws Fault {
if (isOutbound(message)) {
OutputStream outputStream = message.getContent(OutputStream.class);
CachedOutputStream cachedOutputStream = new CachedOutputStream();
message.setContent(OutputStream.class, cachedOutputStream);
message.getInterceptorChain().doIntercept(message);
try {
cachedOutputStream.flush();
CachedOutputStream messageStream = (CachedOutputStream) message.getContent(OutputStream.class);
String currentEnvelopeMessage = IOUtils.toString(messageStream.getInputStream(), "UTF-8");
currentEnvelopeMessage = currentEnvelopeMessage.replaceAll("ns2:", "");
currentEnvelopeMessage = currentEnvelopeMessage.replaceAll(":ns2", "");
messageStream.flush();
messageStream.close();
InputStream replaceInStream = new ByteArrayInputStream(currentEnvelopeMessage.getBytes(StandardCharsets.UTF_8));
IOUtils.copy(replaceInStream, outputStream);
replaceInStream.close();
outputStream.flush();
message.setContent(OutputStream.class, outputStream);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private boolean isOutbound(Message message){
return message == message.getExchange().getOutMessage()
|| message == message.getExchange().getOutFaultMessage();
}
}
有了这个拦截器,我终于可以删除名称空间。 最后一个问题是名称空间xmlns =“ http://www.portalfiscal.inf.br/nfe”应该出现在consStatServ元素中。 在修改JAXB生成的类后,由于删除了所有不必要的名称空间,所以我要做的解决方法只是在ConsStatServ类中创建xmln属性:
public class ConsStatServ {
.
.
.
@XmlAttribute(name = "xmlns", required = true)
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
protected String xmlns = "http://www.portalfiscal.inf.br/nfe";
public String getXmlns() {
return xmlns;
}
}
我知道这个解决方案是一个巨大的难题,但是我找不到其他选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.