2009-05-18 3 views
2

Мне поручили рефакторинг некоторых компонентов, которые использовали xmlbeans, чтобы теперь использовать jaxb. Все идет отлично, пока я не доберусь до места, где предыдущий автор назвал copy() function of one of the XmlObjects. Поскольку все объекты в xmlbeans расширяют XmlObject, мы получаем бесплатную функцию глубокой копии.Как сделать глубокую копию объекта JAXB, например xmlbean XmlObject.copy()?

Jaxb, кажется, не предоставляет это для нас. Каков правильный и простой способ сделать глубокую копию объекта Jaxb?

+0

Мне интересно узнать, почему вы переезжаете из XMLBeans в JAXB, мы используем XMLBeans и рассматриваем сравнивая его с JIXB, чтобы увидеть, если мы можем получить некоторые преимущества в производительности, Какова была ваша мотивация к изменениям? – Tom

+0

Ну, есть несколько причин, основная причина в том, что поддержка перечислений xmlbeans немного фрагментирована, интерфейс сгенерированного кода немного нечетный, и все объекты расширяют XmlObject, и мы предпочли бы, чтобы сгенерированные классы были полностью независимы от чего-либо не входит в стандартную java. Все это, и Jaxb не входит в базовый jdk. –

ответ

3

Вы можете сделать классы JAXB сериализуемыми, а затем глубоким копированием объекта путем сериализации и десериализации. Код может выглядеть примерно так:

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

Вам не нужно делать их сериализуемыми, поскольку вся цель JAXB заключается в сортировке объектов в XML и из него. Вы могли бы маршалл и unmarhsall объект, чтобы сделать копию, но это, вероятно, гораздо менее эффективно, чем писать собственную функцию clone(). – nsayer

+0

+1 Я думаю, что это правильный путь - он дживы с другими предложениями, которые я видел. Спасибо за пример кода. –

+0

Стоит отметить, что в этом решении есть некоторые [незначительные накладные расходы] (http://stackoverflow.com/a/10870833/521799) с использованием 'Object.clone()' непосредственно. Если производительность важна, этого следует избегать ... –

3

Вы можете объявить базовый класс для создаваемых объектов JAXB с использованием аннотаций в XSD ...

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

Вы можете добавить поддержку clonability там с помощью базовый класс xmlbeans как шаблон.

+0

+1 Мне очень нравится эта идея - к сожалению, она не вписывается в наш прецедент (что немного не соответствует норме) –

+0

Duh, такой простой трюк обходит так много проблемы. Ницца! –

3

Вы можете использовать JAXBSource

Допустим, вы хотите глубоко скопировать SourceObject, типа Foo. Создайте 2 JAXBContexts для того же типа:

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

, а затем сделать:

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

Мне нравится это решение, поскольку оно использует структуру JAXB, однако Контекст должен быть создан не как Foo.class, а JAXB, сгенерированное пространство имен схемы. Вы должны указать, что иначе пользователь получит ошибку исключения/времени выполнения из фреймворка, не найдя ObjectFactory. Кроме того, этот пример будет очень полезен при добавлении фактического кода для получения объекта (например, Foo target = targetJAXBContext.createUnmarshaller ...) – count0

5

Вы можете передать этот

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()); 
} 

Это работает для меня.

Все заслуга https://gist.github.com/darrend/821410

+1

Это выглядит более чистым. – Espresso

Смежные вопросы