该问题与JDK 6中的JAXB 2.1.10相关
从昨天开始,我想弄清楚如何在一个字段上与@XmlJavaTypeAdapter
一起定义XmlElementRef
。
从网上我有几个显示这种用法的例子,但它们都使用从值类型的@XmlRootElement
生成的元素名称。
我的问题在于我有一个类型为JAXBElement<T>
为了澄清,让我提出方案。
架构(我无法控制)是这样的:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
targetNamespace="blah_blah"
xmlns:tns="blah_blah" >
<element name="productContext" type="tns:ProductContext" />
<complexType name="ProductContext">
<sequence>
<element name="product" type="tns:Product" minOccurs="0" maxOccurs="1" nillable="true" />
<element name="owner" type="string" />
</sequence>
</complexType>
<complexType name="Product">
<sequence>
<element name="item" type="tns:Item" minOccurs="0" maxOccurs="unbounded" />
</sequence>
<attribute name="id" type="int" use="optional" />
</complexType>
<complexType name="Item">
<sequence>
<element name="name" type="string" />
<element name="category" type="string" />
<element name="range" type="string" />
<element name="price" type="double" minOccurs="0" nillable="true"/>
</sequence>
</complexType>
</schema>
我通过XJC&amp; amp;编译了架构。我得到了以下生成的文件 -
我要解组的XML就像这样 -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<productContext xmlns="blah_blah">
<product id="11">
<item>
<name>item_0</name>
<category>category_0</category>
<range>range_0</range>
<price>300</price>
</item>
<item>
<name>item_1</name>
<category>category_1</category>
<range>range_1</range>
<price>400</price>
</item>
</product>
<owner>Vikas</owner>
</productContext>
我可以将其解组为以下测试类:
package test.jaxb;
import java.io.FileReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
public class Test {
public static void main(String... args) throws Exception {
JAXBContext context = JAXBContext.newInstance(ProductContext.class);
ObjectFactory factory = new ObjectFactory();
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement<ProductContext> productContext = (JAXBElement<ProductContext>) unmarshaller.unmarshal(new FileReader("C:\\test.xml"));
Product product = productContext.getValue().getProduct().getValue();
System.out.println("Product Id : " + product.getId());
System.out.println("Item 0 : " + product.getItem().get(0).getName());
System.out.println("Item 1 : " + product.getItem().get(1).getName());
}
}
运行它会让我:
Product Id : 11
Item 0 : item_0
Item 1 : item_1
我的问题如下:
在ProductContext
班,
我希望java.util.HashMap<String, Item>
取代Product
允许根据项目名称查找项目(我不想更改Product类)
目前ProductContext
课程已获得参考产品,
而不是产品本身
(因为:minOccurs =“0”&amp; nillable =“true”)如下 -
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ProductContext", propOrder = {
"product",
"owner"
})
public class ProductContext {
@XmlElementRef(name = "product", namespace = "blah_blah", type = JAXBElement.class)
protected JAXBElement<Product> product;
..
}
ObjectFactory看起来像:
@XmlRegistry
public class ObjectFactory {
..
/**
* Create an instance of {@link Product }
*
*/
public Product createProduct() {
return new Product();
}
/**
* Create an instance of {@link JAXBElement }{@code <}{@link Product }{@code >}}
*
*/
@XmlElementDecl(namespace = "blah_blah", name = "product", scope = ProductContext.class)
public JAXBElement<Product> createProductContextProduct(Product value) {
return new JAXBElement<Product>(_ProductContextProduct_QNAME, Product.class, ProductContext.class, value);
}
}
我尝试引入名为ProductAdapter
的适配器,如下面的
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ProductContext", propOrder = {
"product",
"owner"
})
public class ProductContext {
@XmlElementRef(name = "product", namespace = "blah_blah", type = JAXBElement.class)
@XmlJavaTypeAdapter(test.jaxb.ProductAdapter.class)
protected HashMap<String, Item> product;
..
}
&安培;适配器为:
package test.jaxb;
import java.util.HashMap;
import java.util.Map.Entry;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class ProductAdapter extends XmlAdapter<JAXBElement<Product>, HashMap<String, Item>> {
@Override
public HashMap<String, Item> unmarshal(JAXBElement<Product> valueType) throws Exception {
HashMap<String, Item> map = new HashMap<String, Item>();
Product product = valueType.getValue();
for(Item item : product.getItem()) {
map.put(item.getName() , item);
}
return map;
}
@Override
public JAXBElement<Product> marshal(HashMap<String, Item> boundType) throws Exception {
ObjectFactory factory = new ObjectFactory();
Product product = factory.createProduct();
for(Entry<String, Item> entry : boundType.entrySet()) {
product.getItem().add(entry.getValue());
}
// return a JAXBElement of Product which is ProductContext Scoped
return factory.createProductContextProduct(product);
}
}
我仍然可以使用Test class -
解组它package test.jaxb;
import java.io.FileReader;
import java.util.Map.Entry;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
public class Test {
public static void main(String... args) throws Exception {
JAXBContext context = JAXBContext.newInstance(ProductContext.class);
ObjectFactory factory = new ObjectFactory();
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement<ProductContext> productContext = (JAXBElement<ProductContext>) unmarshaller.unmarshal(new FileReader("C:\\test.xml"));
/*
Product product = productContext.getValue().getProduct().getValue();
System.out.println("Product Id : " + product.getId());
System.out.println("Item 0 : " + product.getItem().get(0).getName());
System.out.println("Item 1 : " + product.getItem().get(1).getName());
*/
for(Entry<String, Item> entry : productContext.getValue().getProduct().entrySet()) {
System.out.println( "Item name : " + entry.getKey() + " , value : " + entry.getValue().getCategory());
}
}
}
产生以下输出 -
Item name : item_1 , value : category_1
Item name : item_0 , value : category_0
然而问题出在适配器的ValueType
ProductAdapter
的值类型为JAXBElement<Product>
&amp;不是Product
ProductAdapter extends XmlAdapter<JAXBElement<Product>, HashMap<String, Item>>
我不喜欢使用它:
Product
我尝试将适配器增强为 -
public class ProductAdapter extends XmlAdapter<Product, HashMap<String, Item>>
但它在Unmarshalling(没有Map的人口)和&amp; 编组(给出异常 - 无法编组类型“test.jaxb.Product”作为元素,因为它缺少@XmlRootElement注释)
有人可以指导我如何使用@XmlJavaTypeAdapter
没有Adapter的@XmlElementRef(type=JAXBElement)
将JAXBElement作为值返回类型??