С помощью Блейза Дафана - вот окончательное решение, на котором я остановился. Это включает в себя дополнительный демонстрационный код, чтобы помочь другим, кто может оказаться в этой ситуации.
Занятия
ProductList (новый класс упаковки, показывающий, как это работает для нескольких записей Product)
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
import java.util.List;
@XmlRootElement(name="ProductList")
public class ProductList {
@XmlElementWrapper(name="Products")
@XmlElement(name="Product")
public List<Product> products = new ArrayList<Product>();
}
Продукт (с модификациями Блейза)
import org.w3c.dom.Node;
import javax.xml.bind.annotation.*;
@XmlRootElement(name="Product")
@XmlAccessorType(XmlAccessType.FIELD)
public class Product {
@XmlElement(name="CommonProperty")
public String commonProperty="Something";
@XmlAnyElement
public Node extraXml;
}
Main (некоторый демонстрационный код)
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
public class Main {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// Build some arbitrary extra XML and prepare an InputStream
String fragment1 = "<abc><def>Some extra 1</def></abc>";
String fragment2 = "<ghi><jkl>Some extra 2</jkl></ghi>";
Document document1 = factory.newDocumentBuilder().parse(new InputSource(new StringReader(fragment1)));
Document document2 = factory.newDocumentBuilder().parse(new InputSource(new StringReader(fragment2)));
Product product1 = new Product();
product1.commonProperty = "Hello 1";
product1.extraXml=document1.getFirstChild();
Product product2 = new Product();
product2.commonProperty = "Hello 2";
product2.extraXml=document2.getFirstChild();
ProductList productList = new ProductList();
productList.products.add(product1);
productList.products.add(product2);
JAXBContext jc = JAXBContext.newInstance(ProductList.class, Product.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(productList, System.out);
}
}
Окончательный вывод:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProductList>
<Products>
<Product>
<CommonProperty>Hello 1</CommonProperty>
<abc>
<def>Some extra 1</def>
</abc>
</Product>
<Product>
<CommonProperty>Hello 2</CommonProperty>
<ghi>
<jkl>Some extra 2</jkl>
</ghi>
</Product>
</Products>
</ProductList>
Результат!
Но в JBoss это не работает ...
Если вы попробуете это в JBoss 4.2.3.GA или 4.3, вы можете получить
class com.sun.org.apache.xerces.internal.dom.DocumentFragmentImpl nor any of its super class is known to this context.
сообщается об исключении. Это (вероятно) связано с тем, что xercesImpl.jar
в папках JBoss lib
и /lib/endorsed
используют функцию переопределения Java META-INF/Services
, чтобы предотвратить сортировку JDK с использованием внутренних классов. Возможно, вам придется указать альтернативу DocumentBuilderFactory
напрямую, используя следующий подход:
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance("oracle.xml.jaxp.JXDocumentBuilderFactory", this
.getClass().getClassLoader());
Реализация Oracle, кажется, облегчает эти проблемы, возможно, потому, что поддерживает осведомленность о классах узла DOM в контексте JAXB. Эти классы находятся в xdb.jar и xmlparserv2.jar, поставляемых с клиентом Oracle.
Надеюсь, это поможет.