如何通过JAXB Marshalling避免父类字段出现在XML中
解决JAXB序列化子类时包含父类字段的问题
我之前碰到过完全一样的情况——JAXB默认会处理父类的所有可访问属性,哪怕你不想让它们出现在XML里,而且还没法修改父类代码。下面给你几个实用的解决方案,按简洁度排序:
方案1:用@XmlAccessorType限制仅序列化带注解的属性
这是最省心的办法,直接在子类上添加@XmlAccessorType(XmlAccessType.NONE),告诉JAXB只处理带有JAXB注解的属性,父类没有注解的字段自然就被排除了。
修改后的子类代码:
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlTransient; @XmlAccessorType(XmlAccessType.NONE) public class ChildClass extends ParentClass implements Serializable { private String name; private String ID; private String timeStamp; @XmlElement public String getName(){ return this.name; } @XmlElement(name="AccountID") public String getID(){ // 修正原代码中缺少的括号 return this.ID; } @XmlTransient public String getTimeStamp(){ // 修正原代码中变量名大小写不一致的问题 return this.timeStamp; } // Setters ... }
方案2:重写父类getter并添加@XmlTransient
如果子类有很多属性,不想逐个加@XmlElement,可以在子类里重写父类的modded和saved的getter方法,然后给这些重写的方法加上@XmlTransient——JAXB会优先使用子类的方法,从而排除这些字段。
修改后的子类代码:
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessType; @XmlAccessorType(XmlAccessType.PROPERTY) @XmlType(propOrder = {"name", "ID"}) // 指定序列化属性的顺序(可选) public class ChildClass extends ParentClass implements Serializable { private String name; private String ID; private String timeStamp; public String getName(){ return this.name; } @XmlElement(name="AccountID") public String getID(){ return this.ID; } @XmlTransient public String getTimeStamp(){ return this.timeStamp; } // 重写父类的getter并添加@XmlTransient @Override @XmlTransient public boolean isModded() { // 注意boolean类型的getter通常是isXXX,要和父类方法名一致 return super.isModded(); } @Override @XmlTransient public int getSaved() { return super.getSaved(); } // Setters ... }
方案3:自定义XmlAdapter(适合特殊场景)
如果前两种方法都不适用,可以通过适配器将子类转换成一个仅包含需要字段的中间类,序列化时实际处理这个中间类,彻底隔离父类属性。
首先创建适配器类:
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.adapters.XmlAdapter; public class ChildClassAdapter extends XmlAdapter<ChildClassAdapter.AdaptedChild, ChildClass> { // 仅包含需要序列化的字段的中间类 public static class AdaptedChild { private String name; @XmlElement(name="AccountID") private String ID; // Getters and Setters public String getName() { return name; } public void setName(String name) { this.name = name; } public String getID() { return ID; } public void setID(String ID) { this.ID = ID; } } @Override public AdaptedChild marshal(ChildClass child) throws Exception { AdaptedChild adapted = new AdaptedChild(); adapted.setName(child.getName()); adapted.setID(child.getID()); // 只传递需要的字段,忽略父类属性 return adapted; } @Override public ChildClass unmarshal(AdaptedChild adapted) throws Exception { ChildClass child = new ChildClass(); child.setName(adapted.getName()); child.setID(adapted.getID()); // 反序列化时按需还原属性 return child; } }
然后在子类上添加适配器注解:
import javax.xml.bind.annotation.XmlJavaTypeAdapter; @XmlJavaTypeAdapter(ChildClassAdapter.class) public class ChildClass extends ParentClass implements Serializable { // 原有代码不变 }
推荐优先用方案1,代码改动最小且逻辑清晰。另外注意修正原代码里的小问题:getID()缺少括号、timeStamp和timestamp变量名大小写不一致,这些细节也可能导致序列化异常哦。
内容的提问来源于stack exchange,提问作者wolfcubman
相关产品推荐
相关产品推荐

