如果有一些具有相同值的@XmlID带注释的属性,即使它们的类型不同,JAXB也无法成功解组对象,但是马歇尔是好的。
这是一个错误吗?
或者,如何支持该功能?
代码:
package xml;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class MultiID {
static public class LongXmlAdapter extends XmlAdapter<String, Long> {
@Override
public Long unmarshal(String s) {
return Long.parseLong(s);
}
@Override
public String marshal(Long number) {
if (number == null) return "";
return number.toString();
}
}
static public class Element {
private Long id;
@XmlID
@XmlAttribute(required=true)
@XmlJavaTypeAdapter(LongXmlAdapter.class)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
static public class Component {
private Long id;
@XmlID
@XmlAttribute(required=true)
@XmlJavaTypeAdapter(LongXmlAdapter.class)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
private Element elem;
@XmlIDREF
@XmlAttribute(required=true)
public Element getElem() {
return elem;
}
public void setElem(Element e) {
this.elem = e;
}
}
@XmlRootElement
static public class Container {
private List<Element> elemLst = new ArrayList<Element>();
private List<Component> lst = new ArrayList<Component>();
@XmlElementWrapper(name="elemList")
@XmlElement(name="elem")
public List<Element> getElemLst() {
return (elemLst != null)?elemLst:(elemLst = new ArrayList<Element>());
}
public void setElemLst(List<Element> elemLst) {
this.elemLst = elemLst;
}
@XmlElementWrapper(name="componentList")
@XmlElement(name="component")
public List<Component> getLst() {
return (lst != null)?lst:(lst = new ArrayList<Component>());
}
public void setLst(List<Component> lst) {
this.lst = lst;
}
}
static public class XmlSerialization {
public static Object read(String filepath, Class... classesToBeBound) throws FileNotFoundException {
Object entity = null;
try {
File file = new File(filepath);
if(!file.exists()) throw new FileNotFoundException(filepath);
JAXBContext context = JAXBContext.newInstance(classesToBeBound);
Unmarshaller um = context.createUnmarshaller();
entity = um.unmarshal(file);
} catch (JAXBException ex) {
Logger.getLogger(XmlSerialization.class.getName()).log(Level.SEVERE, null, ex);
}
return entity;
}
public static void write(String filePath, Object entity, Class... classesToBeBound) {
File file = new File(filePath);
try {
JAXBContext context = JAXBContext.newInstance(classesToBeBound);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.marshal(entity, file);
} catch (JAXBException ex) {
Logger.getLogger(XmlSerialization.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public Container createContainer() {
Container container = new Container();
for(long i = 1 ; i < 5; ++i) {
Element elem = new Element();
elem.setId(i);
container.getElemLst().add(elem);
Component comp = new Component();
comp.setId(i);
comp.setElem(elem);
container.getLst().add(comp);
}
return container;
}
public void write(String filePath, Container container) {
XmlSerialization.write(filePath, container, Container.class, Component.class, Element.class);
}
public Container read(String filePath) {
Container container = null;
try {
container = (Container)XmlSerialization.read(filePath, Container.class, Component.class, Element.class);
} catch (FileNotFoundException ex) {
Logger.getLogger(MultiID.class.getName()).log(Level.SEVERE, null, ex);
}
return container;
}
public static void main(String[] args) {
MultiID test = new MultiID();
String filePath = "c:\\tmp.xml";
Container c1 = test.createContainer();
test.write(filePath, c1);
Container c2 = test.read(filePath);
filePath = "c:\\tmp2.xml";
test.write(filePath, c2);
}
}
输出:
[tmp.xml]
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<container>
<elemList>
<elem id="1"/>
<elem id="2"/>
<elem id="3"/>
<elem id="4"/>
</elemList>
<componentList>
<component id="1" elem="1"/>
<component id="2" elem="2"/>
<component id="3" elem="3"/>
<component id="4" elem="4"/>
</componentList>
</container>
[tmp2.xml]
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<container>
<elemList>
<elem id="1"/>
<elem id="2"/>
<elem id="3"/>
<elem id="4"/>
</elemList>
<componentList>
<component id="1"/>
<component id="2"/>
<component id="3"/>
<component id="4"/>
</componentList>
</container>
tmp2.xml中的每个“组件”都没有元素引用。 那就是问题所在。 例如,如果我们从100开始更改组件ID,它将按预期工作。
如何解决此问题? 非常感谢。
答案 0 :(得分:1)
XML中的ID必须(a)在整个XML文档中是唯一的,并且(b)有效的XML名称(因此不以数字开头)。不要使用long,而是考虑e1
,e2
等字符串作为元素,c1
...作为组件。
答案 1 :(得分:1)
您的输出是由于您正在使用的JAXB (JSR-222)实施中的错误造成的。使用JDK 1.7.0中包含的JAXB impl为Mac运行示例代码,EclipseLink JAXB (MOXy)我得到了tmp2.xml的预期结果。
<强> tmp2.xml 强>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<container>
<elemList>
<elem id="1"/>
<elem id="2"/>
<elem id="3"/>
<elem id="4"/>
</elemList>
<componentList>
<component elem="1" id="1"/>
<component elem="2" id="2"/>
<component elem="3" id="3"/>
<component elem="4" id="4"/>
</componentList>
</container>