Binding JAXB

Pessoal estou utilizando JAXB para montar meus arquivos xml, baixei o plugin do eclipse para gerar as classes com base nos schemas, o arquivo montado é uma nota fiscal eletrônica, estou tendo problemas no namespace do xml.

Arquivo Gerado

  <?xml version="1.0" encoding="UTF-8"?>
     <NFe xmlns="http://www.portalfiscal.inf.br/nfe" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">
         <infNFe Id="NFe51080906088741000586550010000028441200192708" versao="1.10">
  ...

Mas a forma correta seria assim

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
   <NFe xmlns="http://www.portalfiscal.inf.br/nfe">
      <infNFe xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Id="NFe51080906088741000586550010000025940000000101" versao="1.10">

Estou gerando meu arquivo da seguinte forma.

   Marshaller marshaller = context.createMarshaller();
			JAXBElement<TNFe> element = ( new ObjectFactoryNFe()).createNFe(nfe);
			marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT , Boolean.FALSE );

			ByteArrayOutputStream result = new ByteArrayOutputStream();
			marshaller.marshal( element, result );

Alguém ja passou por isso e poderia me ajudar por favor

Grato

Ola Fernando, qual e’ o erro, ou mensagem que esta lhe retornando ?

Ola Mateus tudo bem?

Quando tento transmitir o arquivo ou vou valida-lo é retornado um erro de que o cabeçalho está incorreto.
O arquivo gerado por mim parece estar incorreto na declaração dos namespaces.

Grato

Fernando, qual plugin do Eclipse vc tah usando?

Não há nada de errado com plugins dele, o problema é que o JAXB é bom demais. :smiley:

Deixa eu explicar:

Assim como o eclipse, outras ferramentas não funcionam com o NS2, vai falar para eles que não esta errado e que o JAXB só quiz fazer da maneira certa?

Pois é… Não consegui fazer ele parar de gerar o ns2 assim como o amigo descreveu no post, então foi obrigado à atacar para a apelação, pois a definição de namespace no jaxb é simples…

@XmlRootElement(name=“urlset”,namespace=“http://www.sitemaps.org/schemas/sitemap/0.9”)
@XmlAccessorType(XmlAccessType.FIELD)

Porém SEMPRE ele gera com o maldito ns2 e as ferramentas que vão ler “quase” sempre se batem por causa dele.

Não tenho nada contra o jaxb, pelo contrário, ele me ajuda MUITO, porém ajuda tanto e faz as coisas tão certo que acaba atrapalhando quando quem vai ler do outro lado não o faz.

Por isso eu escrevi um artigo no meu blog com a solução para o problema:

SEQUE O LINK:

DIGO E REPITO: Não é a melhor solução, mas resolve o problema na hora e você não priva-se de usar os benefícios do JAXB, já que ele só é acionado como forma de AJUSTE do xml depois do parse:

Abraços

Olá Pessoal,

Estou tendo problemas para gerar os beans da Nota Fiscal Eletronica com JAXB, parece que um XSD faz include do outro e dá pau…
Vocês consguiram fazer funcionar numa boa?

O comando que tentei usar é o seguinte:
xjc -d …/…/java/ cabecMsg_v1.02.xsd enviNFe_v1.10.xsd retEnviNFe_v1.10.xsd consReciNFe_v1.10.xsd retConsReciNFe_v1.10.xsd cancNFe_v1.07.xsd retCancNFe_v1.07.xsd consSitNFe_v1.07.xsd retConsSitNFe_v1.07.xsd consStatServ_v1.07.xsd retConsStatServ_v1.07.xsd consCad_v1.01.xsd leiauteConsultaCadastro_v1.01.xsd -h

Abraço

[quote=andrefariagomes]Olá Pessoal,

Estou tendo problemas para gerar os beans da Nota Fiscal Eletronica com JAXB, parece que um XSD faz include do outro e dá pau…
Vocês consguiram fazer funcionar numa boa?

O comando que tentei usar é o seguinte:
xjc -d …/…/java/ cabecMsg_v1.02.xsd enviNFe_v1.10.xsd retEnviNFe_v1.10.xsd consReciNFe_v1.10.xsd retConsReciNFe_v1.10.xsd cancNFe_v1.07.xsd retCancNFe_v1.07.xsd consSitNFe_v1.07.xsd retConsSitNFe_v1.07.xsd consStatServ_v1.07.xsd retConsStatServ_v1.07.xsd consCad_v1.01.xsd leiauteConsultaCadastro_v1.01.xsd -h

Abraço[/quote]

pra quem tiver a mesma dúvida…

http://www.technopub.com.br/index.php?page=artigos&id=10

[quote=isaiasa]Não há nada de errado com plugins dele, o problema é que o JAXB é bom demais. :smiley:

Deixa eu explicar:

Assim como o eclipse, outras ferramentas não funcionam com o NS2, vai falar para eles que não esta errado e que o JAXB só quiz fazer da maneira certa?

Pois é… Não consegui fazer ele parar de gerar o ns2 assim como o amigo descreveu no post, então foi obrigado à atacar para a apelação, pois a definição de namespace no jaxb é simples…

@XmlRootElement(name=“urlset”,namespace=“http://www.sitemaps.org/schemas/sitemap/0.9”)
@XmlAccessorType(XmlAccessType.FIELD)

Porém SEMPRE ele gera com o maldito ns2 e as ferramentas que vão ler “quase” sempre se batem por causa dele.

Não tenho nada contra o jaxb, pelo contrário, ele me ajuda MUITO, porém ajuda tanto e faz as coisas tão certo que acaba atrapalhando quando quem vai ler do outro lado não o faz.

Por isso eu escrevi um artigo no meu blog com a solução para o problema:

SEQUE O LINK:

DIGO E REPITO: Não é a melhor solução, mas resolve o problema na hora e você não priva-se de usar os benefícios do JAXB, já que ele só é acionado como forma de AJUSTE do xml depois do parse:

Abraços[/quote]

Li o artigo acima, e gostaria de saber aí se a galera não descobriu uma maneira melhor de resolver isso.

Estou começando agora um projeto com NFe e já acabei de topar com esse mesmo problema do JAX-B. Vi que esse artigo tem mais de 1 ano já, então a pergunta é: já conseguiu uma outra forma menos “gambiarroza” de resolver isso? Eu vi que acertando os elementos dos beans gerados pelo JAXB ele vai mudando a forma de como utiliza os prefixos, mas não cheguei a um consenso a respeito.

Se descobriram outra forma, por favor, postem aí como funcionado.

Obrigado

SIm, há solução de personalizar os namespaces, no link:

http://blogs.sun.com/enterprisetechtips/entry/customizing_jaxb

Você encontra a solução.

Você precisa criar uma classe que estenda NamespacePrefixMapper vide:

[code]NamespacePrefixMapper m = new PreferredMapper();
marshal(jc, e, m);

public static class PreferredMapper extends NamespacePrefixMapper {
@Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
return “mappedNamespace” + namespaceUri;
}
}[/code]

Depois no seu marshaller voce seta:

final Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); marshaller.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", new NamespacePrefixMapperImpl("http://www.isotc211.org/2005/gmd"));

Abraço

Mesmo assim… se eu mando retornar “”, ele tenta colocar o default, que no caso é aquele ns2 indesejado…
Falta implementar mais alguma coisa???

Quais das opções abaixo resolvem teu problema?

  • Gerar o xml sem nenhum namespace? S: Não anote nenhum nameSpace no seu bean que foi anotado para trabalhar com JAXB.

  • Gerar o xml com 1 único namespace? S: se for isso, veja exemplo abaixo.

Implementação:

[code]The third marshalling done by the JAXBSample program uses a NamespacePrefixMapper class as follows:

m = new DeclareOnTopMapper();
marshal(jc, e, m);

public static class DeclareOnTopMapper extends PreferredMapper {
@Override
public String[] getPreDeclaredNamespaceUris() {
return new String[] {“a”, “b”};
// return new String[] {“a”}; // Aqui ao inves de retornares “a”,“b”, retorne só a
}
}[/code]

[quote=isaiasa]Quais das opções abaixo resolvem teu problema?

  • Gerar o xml sem nenhum namespace? S: Não anote nenhum nameSpace no seu bean que foi anotado para trabalhar com JAXB.

  • Gerar o xml com 1 único namespace? S: se for isso, veja exemplo abaixo.

Implementação:

[code]The third marshalling done by the JAXBSample program uses a NamespacePrefixMapper class as follows:

m = new DeclareOnTopMapper();
marshal(jc, e, m);

public static class DeclareOnTopMapper extends PreferredMapper {
@Override
public String[] getPreDeclaredNamespaceUris() {
return new String[] {“a”, “b”};
// return new String[] {“a”}; // Aqui ao inves de retornares “a”,“b”, retorne só a
}
}[/code]
[/quote]

Na verdade nenhum dos dois. O problema meu, que é o mesmo do Marco, é que o JAXB parece não permitir a utilização de tags não prefixadas para namespaces diferentes. Por exemplo, o seguinte XML nunca poderia ser marshallizado através do JAXB:

<tagRoot xmlns="http://www.example.org/">

    <subTag1>valor1</subTag1>
    <subTag2>valor2</subTag2>
    <subTag3>valor3</subTag3>

    <subTag4 xmlns="http://www.example2.org/">
       <subSubTag1>valor1</subSubTag1>
       <subSubTag2>valor2</subSubTag2>
       <subSubTag3>valor3</subSubTag3>
    </subTag4>

</tagRoot>

O que o JAXB faria no caso de tentar marshallizar os beans correspondentes ao XML acima é:

<tagRoot xmlns="http://www.example.org/" xmlns:ns2="http://www.example2.org/">

    <subTag1>valor1</subTag1>
    <subTag2>valor2</subTag2>
    <subTag3>valor3</subTag3>

    <ns2:subTag4>
       <ns2:subSubTag1>valor1</ns2:subSubTag1>
       <ns2:subSubTag2>valor2</ns2:subSubTag2>
       <ns2:subSubTag3>valor3</ns2:subSubTag3>
    </ns2:subTag4>

</tagRoot>

Enfim… teria alguma maneira de fazer com que o JAXB marshalize para o primeiro XML ???

Já tentei com todas as formas do NamespacePrefixMapper, utilizando todos os métodos ali, e nada até agora.
A solução até o momento é porcamente remover os prefixos com replace(…). Porca mesmo!!!

Obrigado

Carlos

Teu caso é diferente do caso que passei.

Mas tenho um teste para propor:

Baseando-se no exemplo abaixo, que é nosso alvo:

1. <tagRoot xmlns="http://www.example.org/"> 2. 3. <subTag1>valor1</subTag1> 4. <subTag2>valor2</subTag2> 5. <subTag3>valor3</subTag3> 6. 7. <subTag4 xmlns="http://www.example2.org/"> 8. <subSubTag1>valor1</subSubTag1> 9. <subSubTag2>valor2</subSubTag2> 10. <subSubTag3>valor3</subSubTag3> 11. </subTag4> 12. 13. </tagRoot>

Tu poderias tentar colocar o conteudo de subTag4 em uma outra classe anotada com o namespace http://www.example2.org unicamente e depois acrescer esse xml após o marshall à o seu conteudo da seguinte forma:

[code]Document[] docs = new Document[2];

doc[0] = (Document) MyMarshaller.marshall(myEntity1); // com o ns http://www.example.org/"

doc[1] = (Document) MyMarshaller.marshall(myEntity1); // com o ns http://www.example2.org/[/code]

e depois montar o xml:

for (Document doc : docs) { if (doc != null) { Node node = finalDocument.importNode(doc.getFirstChild(), true); rootElement.appendChild( node ); } }

Eu não consegui testar essa solução, por isso é uma sugestão, vou ver se consigo fazer o mesmo teste quando eu chegar em casa, estou meio enrolado aqui no serviço agora. Mas ACREDITO que deva resolver, porque note que os marshall’s são feitos de forma separada, se isso é uma deficiencia mesmo do JAXB, após o marshall a “CACA” ja foi feita e nós sabemos que esses problemas só ocorrem quando temos mais de 1 ns… no caso será 1 para cada documento.

Continuo em alerta para tentarmos resolver o problema e termos uma solução mais limpa.

Abraço

Pessoal nada ainda ? para a solução deste problema ?

estou trabalahndo nisto, se alguem ja resolveu ou tem a solução, por favor compartilhe.

Ola Isaiasa,

vi seu post sobre os prefixos nas namespace da NF-e, vi que se vc manter as classes(objetos que representão o xml de consumo do serviço) ex: ConsStatServ.java estar no pacote br.inf.portalfiscal.nfe.wsdl.nfestatusservico2\ vc não tera esses prefixos gerados.

Notei que isso traz problemas quando vc limpa e controi a aplicação gerando os stubs novamente vc perdia a alteração que vc havia feito nas classes:

1- a configuração na classe ObjectFactory gerada pelo Cliente WS(public ConsStatServ createConstatSet()),
2 - uma anotação na NfeCabecMsg()(classe tambem gerada pelo cliente ws)

ex:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "content"
})
@XmlRootElement(name = "nfeCabecMsg")
public class NfeCabecMsg {

se eu não der clean and build tudo blz, pois posso apenas constuir sem limpar, assim não perco o que fiz.

agora pergunto, tem alguma maneira melhor de fazer isto ? para que eu possa usar o gerador do cliente e configura-lo a ponto de não precisar fazer essas alterações manualmente ? ex: para podermos gerar os stubs de maneira correta com o método de consumo do serviço aceitando 2 parametros(nfeCabecMsg e NfeDadosMsg) temos que “editar atributos do serviço web” para colocar a linha XadditionalHeaders para true, após atualizado a referencia do serviço web ou limpado e construindo ele gera tudo novamente, de maneira correta.