如何在JAXB中处理多个@XmlID

时间:2012-09-29 09:22:54

标签: java jaxb

如果有一些具有相同值的@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,它将按预期工作。

如何解决此问题? 非常感谢。

2 个答案:

答案 0 :(得分:1)

XML中的ID必须(a)在整个XML文档中是唯一的,并且(b)有效的XML名称(因此不以数字开头)。不要使用long,而是考虑e1e2等字符串作为元素,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>