sexta-feira, 30 de novembro de 2012

JAXB : unexpected element (uri:"http://...", local:"..."). Expected elements are (none)

Após a geração do código Java com o utilitário xjc a partir dos XSDs, e efectuado o código de marshall/unmarshall, ao usar o respectivo código ocorrem erros como os a seguir descritos.

Unmarshall


Erro durante o unmarshall:

unexpected element (uri:"http://.../.../...", local:"MinhaBase"). Expected elements are (none)


Aparentemente poderá ser um problema no XML a descodificar. Contudo se se tiver a certeza que o problema não está no XML a descodificar, então poderá estar a ocorrer um problema relacionado com a ausência da anotação @XmlRootElement na classe base do esquema gerado. Para verificar isto basta abrir a classe base do esquema gerado e verificar se a tag @XmlRootElement está presente. Se estiver o problema é outro que o descrito a seguir.

Resumidamente, isto não é um bug do JAXB. A ausência da anotação está relacionada com a impossibilidade do xjc determinar com exactidão qual a classe raiz do esquema. Em caso de dúvida o xjc não coloca esta tag.

A solução não é nada complicada.

Basta alterar a linha de código (onde está reader poderá estar outro tipo qualquer que seja aceite):

resultadoUnmarshal = (MeuTipoBase) unmarshaller.unmarshal(reader);

Por:

JAXBElement root = unmarshaller.unmarshal(new StreamSource(reader), MeuTipoBase.class);
resultadoUnmarshal = root.getValue();



Marshall

Erro durante o marshall:

com.sun.istack.internal.SAXException2: unable to marshal type "pt.MeuTipoBase" as an element because it is missing an @XmlRootElement annotation

Aqui nota-se claramente que o problema está relacionado com a falta da anotação @XmlRootElement na classe base. Ver este artigo para mais detalhes.

A solução aqui é também simples.

Em primeiro lugar é necessário abrir a classe ObjectFactory onde está a classe MeuTipoBase.

Procurar por algo semelhante a

@XmlElementDecl(namespace = "http://.../.../...", name = "MinhaBase")
public JAXBElement create
MinhaBase(MeuTipoBase, value) {
        return new JAXBElement<
MeuTipoBase>(_MINHA_BASE_QNAME, MeuTipoBase.class, null, value);
}


Ver a classe ObjectFactory facilita na obtenção dos parametros correctos para o objecto QName que terá de ser criado.


No nosso código substituir a linha (ou linha semelhante)

marshaller.marshal(instanciaAcodificar, System.out);

Por

marshaller.marshal(new JAXBElement(new QName("http://.../.../..", "MinhaBase"), MeuTipoBase.class, null, instanciaAcodificar), System.out);


Os parametros usados para criar a instância de QName são as que estão na linha do ObjectFactory

@XmlElementDecl(namespace = "http://.../.../...", name = "MinhaBase")


A não ser que o problema esteja entre a cadeira e o teclado, terão estes problemas resolvidos.

Sem comentários: