web-dev-qa-db-fra.com

Est-il possible de personnaliser le préfixe d'espace de noms que JAXB utilise lors du marshaling vers une chaîne?

Par exemple, j'ai un schéma simple qui importe un autre schéma. Le deuxième schéma (urn: just: attributes, just-attributes.xsd) définit simplement un groupe d'attributs.

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.example.org/MySchema"
    xmlns:tns="http://www.example.org/MySchema" 
    elementFormDefault="qualified"
    xmlns:ja="urn:just:attributes">

    <import schemaLocation="just-attributes.xsd" namespace="urn:just:attributes"/>

    <element name="MyElement">
        <complexType>
            <attributeGroup ref="ja:AttributeGroup"/>
        </complexType>
    </element>
</schema>

J'utilise la tâche Metro xjc Ant pour générer des classes à partir de ce schéma. Le problème que je rencontre est que l'application tierce avec laquelle j'interagis est particulière aux espaces de noms. Dans ce cas, j'ai besoin d'une valeur de chaîne, je dois donc la sérialiser. J'utilise du code passe-partout pour cela.

private static <T> String marshal(T object) throws JAXBException{
    OutputStream outputStream = new ByteArrayOutputStream();
    JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.marshal(object, outputStream);
    return outputStream.toString();
}

Ce qui me donne quelque chose comme

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:MyElement xmlns:ns1="urn:just:attributes" xmlns:ns2="http://www.example.org/MySchema" ns1:attrib1="1234" ns1:attrib2="5678"/>

Le problème que j'ai est que ce tiers attend quelque chose comme xmlns:thirdpartyns="urn:just:attributes", c'est-à-dire qu'ils analysent en fonction du nom donné à l'espace de noms. Il a pour être des "tiers-partenaires" pour que leur logiciel fonctionne.

Quelqu'un connaît-il un moyen de contourner cela, à moins de faire une recherche et un remplacement dans la chaîne résultante? Une règle de liaison personnalisée peut-être?

25
user197614

http://hwellmann.blogspot.com/2011/03/jaxb-marshalling-with-custom-namespace.html

Cela montre comment procéder.

Un autre: http://www.systemmobile.com/?p=28

Clés au cas où ce lien mourrait aussi:

la classe NamespacePrefixMapper, trouvée dans le package com.Sun.xml.bind.marshaller. La classe abstraite a une méthode à implémenter:

public abstract String getPreferredPrefix(  
     String namespaceUri,         
     String suggestion,         
     boolean requirePrefix); 

puis

Marshaller marshaller =        
    jaxbContext.createMarshaller();        
marshaller.setProperty(”com.Sun.xml.bind.namespacePrefixMapper”,        
    new MyNamespacePrefixMapper());  

Si vous utilisez également javax.xml.xpath.XPath, votre NamespacePrefixMapper peut également implémenter javax.xml.namespace.NamespaceContext, en centralisant la personnalisation de votre espace de noms dans une seule classe.

27
DaveC

J'ai testé ça dans Java SE6 et cela nécessite un petit changement par rapport à la solution pour Java SE 5 (comme décrit ci-dessus ):

    Marshaller m = context.createMarshaller();
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
    m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
    m.setProperty("com.Sun.xml.internal.bind.namespacePrefixMapper", mapper);

Ainsi, la troisième propriété ci-dessus contient le .internal. Supplémentaire dans le nom du package par rapport à la version Java SE5. Ce que je n'ai pas encore découvert, c'est comment dire au Marshaller quel URI d'espace de noms devient l'espace de noms par défaut (""). Si je remplace la méthode getPreferredPrefix () et renvoie une chaîne vide, le Marshaller a des problèmes avec l'écriture des attributs de l'espace de noms par défaut (dans ce cas, il crée un nouvel espace de noms appelé ns1)

11
basZero

J'avais la même question. Dans package-info.Java (si vous ne l'avez pas, vous pouvez simplement le créer manuellement) ajoutez la partie xmlns:

@javax.xml.bind.annotation.XmlSchema(xmlns = {
        @javax.xml.bind.annotation.XmlNs(namespaceURI = "urn:just:attributes", prefix = "thirdpartyns") }, 
        elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
7
Weslor

Il existe un moyen de le faire, qui utilise une classe d'implémentation JAXB interne appelée NamespacePrefixMapper. Dans le JAXB RI, c'est dans com.Sun.xml.bind.marshaller, mais en Java6, c'est en com.Sun.xml.internal.bind.marshaller.

Il s'agit d'une classe abstraite, que vous pouvez sous-classer et implémenter la méthode abstraite qui mappe les URI d'espace de noms sur des préfixes.

Vous injectez ensuite une instance de cette sous-classe dans le marshaller:

JAXBContext context = ...
Marshaller marshaller = context.createMarshaller();
NamespacePrefixMapper prefixMapper = new MyPrefixMapperImpl();
marshaller.setProperty("com.Sun.xml.bind.namespacePrefixMapper", prefixMapper);

Le nom de la propriété va être différent pour la version Java6, mais vous avez l'idée.

Notez qu'il s'agit d'une classe d'implémentation JAXB interne, il n'y a donc aucune garantie qu'elle sera présente dans les futures versions.

0
skaffman