JAXB注释 - 如何创建XmlIDRef元素列表,将id值作为属性而不是元素正文文本?

mar*_*hon 5 java jaxb xml-serialization

更新 - 请参阅底部的编辑

IDRefs/keyrefs似乎可以在JAXB注释中使用,但ref最终是元素文本.

我希望ref成为元素的属性.

例如,给定此对象模型:

@XmlType
public class Employee {
    @XmlID
    @XmlAttribute
    String name;
    @XmlAttribute
    int years;
    @XmlAttribute
    String foo;
}

@XmlType
public class Office {
    @XmlAttribute
    String name;
    @XmlElementWrapper
    @XmlElement(name = "employee")
    List<Employee> employees;
}

@XmlRootElement
public class Company {
    @XmlElementWrapper
    @XmlElement(name = "office")
    List<Office> offices;
    @XmlElementWrapper
    @XmlElement(name = "employee")
    List<Employee> employees;
}
Run Code Online (Sandbox Code Playgroud)

我希望外化的xml格式最终看起来像这样:

<company>
    <offices>
        <office name="nyc">
            <employees>
                <!--*** id ref to employee name ***-->
                <employee ref="alice"/>
                <employee ref="bob"/>
            </employees>
        </office>
        <office name="sf">
            <employees>
                <employee ref="connie"/>
                <employee ref="daphne"/>
            </employees>
        </office>
    </offices>
    <employees>
        <!-- *** name is the id *** -->
        <employee name="alice" years="3" foo="bar"/>
        <employee name="bob" years="3" foo="bar"/>
        <employee name="connie" years="3" foo="bar"/>
        <employee name="daphne" years="3" foo="bar"/>
    </employees>
</company>
Run Code Online (Sandbox Code Playgroud)

相反,我能做的最好的就是这个(使用上面java代码中列出的注释):

<company>
    <offices>
        <office name="nyc">
            <employees>
                <employee>alice</employee>
                <employee>bob</employee>
            </employees>
        </office>
        <office name="sf">
            <employees>
                <employee>connie</employee>
                <employee>daphne</employee>
            </employees>
        </office>
    </offices>
    <employees>
        <employee name="alice" years="3" foo="bar"/>
        <employee name="bob" years="3" foo="bar"/>
        <employee name="connie" years="3" foo="bar"/>
        <employee name="daphne" years="3" foo="bar"/>
    </employees>
</company>
Run Code Online (Sandbox Code Playgroud)

有没有办法可以强制idref值成为员工的属性,而不是元素正文?我知道我可以用XML Schema做到这一点,但是如果可能的话我想坚持注释.

谢谢.

编辑 Torious下面的解决方案几乎可以正常工作,但在某些情况下它并不能完全正常工作.

如果"office"元素位于(在xml文件中)办公室引用的"employee"元素之前,则解组失败.找不到员工引用,EmployeeRef包装器具有null员工对象.如果"员工"是第一个,它就有效.

这不会是一个很大的问题,但是编组方法会先把"办公室"放在首位,这样试图解组刚刚编组的东西就会失败.

在Torious的回答中编辑2评论解决了订购问题.

Tor*_*ous 4

解决方案是使用XmlAdapter将 an 包装Employee在新类型 的实例中的 ,EmployeeRef它指定如何映射 XML id ref:

@XmlType
public class Office {

    @XmlAttribute
    String name;

    @XmlElementWrapper
    @XmlElement(name="employee")
    @XmlJavaTypeAdapter(EmployeeAdapter.class) // (un)wraps Employee
    List<Employee> employees;
}

@XmlType
public class EmployeeRef {

    @XmlIDREF
    @XmlAttribute(name="ref")
    Employee employee;

    public EmployeeRef() {
    }

    public EmployeeRef(Employee employee) {
        this.employee = employee;
    }
}

public class EmployeeAdapter extends XmlAdapter<EmployeeRef, Employee> {

    @Override
    public EmployeeRef marshal(Employee employee) throws Exception {
        return new EmployeeRef(employee);
    }

    @Override
    public Employee unmarshal(EmployeeRef ref) throws Exception {
        return ref.employee;
    }
}
Run Code Online (Sandbox Code Playgroud)

祝你好运。