2

如果有一些具有相同值的@XmlID 注释属性,即使它们是不同的类型,JAXB 也无法成功解组对象,但是 marshall 是好的。

它是一个错误吗?

否则,如何支持该功能?

代码:

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,它将按预期工作。

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

4

2 回答 2

1

XML 中的 ID 必须 (a) 在整个 XML 文档中是唯一的,并且 (b) 有效的 XML 名称(因此不能以数字开头)。与其使用 long,不如为元素考虑字符串,如e1,e2等,为c1组件考虑 ...。

于 2012-09-29T14:11:34.267 回答
1

您的输出是由于您正在使用的JAXB (JSR-222)实现中的错误造成的。使用 JDK 1.7.0 for Mac 和EclipseLink JAXB (MOXy)中包含的 JAXB impl 运行您的示例代码,我得到了 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>
于 2012-09-30T10:27:06.217 回答