JAXB反序列化后保留父子关系,为MenuItem生成getParent方法
我刚好处理过类似的场景,不用手动循环就能给子菜单自动绑定父节点,这里有两个比较简便的实现方式:
方法一:利用JAXB的UnmarshalListener自动绑定
JAXB的反序列化过程可以通过监听器拦截对象的创建和绑定,我们可以在这个阶段自动给子节点设置父引用:
给MenuItem类添加parent字段和getter
不管是手动编写还是自动生成的类,先给MenuItem补充以下代码:private MenuItem parent; public MenuItem getParent() { return parent; } // 内部使用的setter,无需对外暴露 void setParent(MenuItem parent) { this.parent = parent; }创建自定义UnmarshalListener
重写afterUnmarshal方法,这个方法会在每个对象反序列化完成后触发,其中parent参数就是当前对象的父节点:class MenuUnmarshalListener extends Unmarshaller.Listener { @Override public void afterUnmarshal(Object target, Object parent) { // 仅当当前对象和父对象都是MenuItem时,绑定父引用 if (target instanceof MenuItem && parent instanceof MenuItem) { ((MenuItem) target).setParent((MenuItem) parent); } } }反序列化时绑定监听器
在创建Unmarshaller实例时设置这个监听器,反序列化过程中就会自动完成父节点绑定:JAXBContext context = JAXBContext.newInstance(MenuRootClass.class); Unmarshaller unmarshaller = context.createUnmarshaller(); unmarshaller.setListener(new MenuUnmarshalListener()); MenuRootClass menu = (MenuRootClass) unmarshaller.unmarshal(new File("menu.xml"));完成后每个子MenuItem的
getParent()就能直接返回父节点,完全不需要手动循环遍历。
方法二:通过JAXB绑定文件生成带父节点逻辑的代码
如果你的MenuItem类是从XSD自动生成的,可以通过绑定文件让生成的代码自动包含父节点的设置逻辑,避免每次生成后手动修改:
编写binding.xml绑定文件
添加自定义规则,给MenuItem生成parent字段,同时修改子节点的添加方法,自动设置父引用:<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" version="2.1"> <jaxb:bindings schemaLocation="your-menu-schema.xsd" node="/xs:schema"> <!-- 给MenuItem类添加parent字段 --> <jaxb:bindings node="xs:complexType[@name='MenuItem']"> <jaxb:property name="parent"> <jaxb:baseType name="com.your.package.MenuItem"/> <jaxb:javadoc>Parent menu item reference</jaxb:javadoc> </jaxb:property> <!-- 修改子节点的添加方法,自动绑定父节点 --> <jaxb:bindings node="xs:sequence/xs:element[@name='menuItem']"> <jaxb:method name="addMenuItem"> <jaxb:code> $1.setParent(this); </jaxb:code> </jaxb:method> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>用绑定文件生成代码
使用xjc命令生成代码时指定绑定文件:xjc -d generated -b binding.xml your-menu-schema.xsd生成的MenuItem类会自动包含parent字段和getter,并且添加子节点时会自动设置父引用,反序列化后直接就能调用
getParent()。
补充说明
如果是手动编写的MenuItem类,方法一最直接高效;如果是基于XSD生成的类,方法二更适合,能维持代码的自动生成特性,避免重复修改。两种方式都不需要在反序列化后手动循环处理父节点绑定。
内容的提问来源于stack exchange,提问作者Rapster

