2009-05-18 8 views
2

J'ai été chargé de refactoriser des composants qui utilisaient xmlbeans pour utiliser jaxb. Tout va bien, jusqu'à ce que j'arrive à un endroit où l'auteur précédent a appelé le copy() function of one of the XmlObjects. Puisque tous les objets dans xmlbeans étendent XmlObject, nous obtenons gratuitement la fonction de copie magique. Jaxb ne semble pas fournir cela pour nous. Quelle est la manière correcte et simple de faire une copie profonde d'un objet Jaxb?Comment faire une copie profonde de l'objet JAXB comme xmlbean XmlObject.copy()?

+0

Je suis curieux de savoir pourquoi vous vous déplacez de XMLBeans à JAXB, nous utilisons XMLBeans et avons envisagé la comparer à JIXB pour voir si nous pouvons obtenir des avantages de performance, Quelle était ta motivation pour le changement? – Tom

+0

Eh bien, il y a quelques raisons, la raison principale étant que le support de xmlbeans enum est un peu sommaire, l'interface du code généré est un peu étrange et tous les objets étendent XmlObject et nous préférerions que les classes générées soient complètement indépendantes de tout pas inclus dans Java standard. Tout cela, et Jaxb n'est pas inclus dans la base jdk. –

Répondre

3

Vous pouvez rendre vos classes JAXB sérialisables, puis copier en profondeur un objet en le sérialisant et en le désérialisant. Le code pourrait ressembler à:

Object obj = ... // object to copy 

ObjectOutputStream out = new ObjectOutputStream(new ByteArrayOutputStream()); 
out.writeObject(obj); 
byte[] bytes = baos.toByteArray(); 

ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes)); 
Object copy = in.readObject(); 
+0

Vous n'avez pas vraiment besoin de les rendre sérialisables, puisque l'objectif derrière JAXB est de rassembler des objets depuis et vers XML. Vous pouvez marshall et unmarhsall l'objet pour faire une copie, mais c'est probablement beaucoup moins efficace que d'écrire votre propre fonction clone(). – nsayer

+0

+1 Je pense que c'est la bonne façon - il jives avec d'autres suggestions que j'ai vu. Merci pour le code d'exemple. –

+0

Il est à noter qu'il y a une certaine surcharge [non-négligeable] (http://stackoverflow.com/a/10870833/521799) dans cette solution plutôt que d'utiliser 'Object.clone()' directement. Si la performance est importante, cela devrait être évité ... –

3

Vous pouvez déclarer une classe de base pour les objets JAXB générés à l'aide d'une annotation dans le XSD ...

<xsd:annotation> 
    <xsd:appinfo> 
    <jaxb:globalBindings> 
     <xjc:superClass name="com.foo.types.support.JaxbBase" /> 
    </jaxb:globalBindings> 
    </xsd:appinfo> 
</xsd:annotation> 

Vous pouvez ajouter le support clonabilité il en utilisant la Classe de base xmlbeans en tant que modèle.

+0

+1 J'aime vraiment cette idée - malheureusement, elle ne rentre pas dans notre cas d'utilisation (ce qui est un peu en dehors de la norme) –

+0

Duh, une astuce si simple contourne tellement problèmes. Agréable! –

3

Vous pouvez utiliser JAXBSource

Dites que vous souhaitez copier en profondeur un SourceObject, de type Foo. Créer 2 JAXBContexts pour le même type:

JAXBContext sourceJAXBContext = JAXBContext.newInstance("Foo.class"); 
JAXBContext targetJAXBContext = JAXBContext.newInstance("Foo.class"); 

puis faites:

targetJAXBContext.createUnmarshaller().unmarshal(
    new JAXBSource(sourceJAXBContext,sourceObject); 
+0

J'aime cette solution car elle utilise le framework JAXB, cependant le Context doit être créé non pas comme Foo.class mais avec l'espace de noms de schéma généré par JAXB. Vous devez le signaler sinon l'utilisateur obtiendra une erreur d'exception/d'exécution de la part de l'infrastructure qui ne parvient pas à trouver ObjectFactory. De plus, l'exemple aurait grandement avantage à ajouter le code réel pour obtenir l'objet (par exemple, Foo target = targetJAXBContext.createUnmarshaller ...) – count0

5

Vous pouvez consulter cette

public static <T> T deepCopyJAXB(T object, Class<T> clazz) { 
    try { 
    JAXBContext jaxbContext = JAXBContext.newInstance(clazz); 
    JAXBElement<T> contentObject = new JAXBElement<T>(new QName(clazz.getSimpleName()), clazz, object); 
    JAXBSource source = new JAXBSource(jaxbContext, contentObject); 
    return jaxbContext.createUnmarshaller().unmarshal(source, clazz).getValue(); 
    } catch (JAXBException e) { 
     throw new RuntimeException(e); 
    } 
} 

public static <T> T deepCopyJAXB(T object) { 
    if(object==null) throw new RuntimeException("Can't guess at class"); 
    return deepCopyJAXB(object, (Class<T>) object.getClass()); 
} 

Il fonctionne pour moi.

Tout le crédit va à https://gist.github.com/darrend/821410

+1

Cela semble plus propre. – Espresso

Questions connexes