【发布时间】:2012-03-28 07:20:39
【问题描述】:
我想知道 JAXB 中是否支持不同版本的类。 我对此的看法:xml 是类的一种持久性对象(序列化值),但类对象可以因开发而改变(例如扩展功能)。有什么方法可以知道仅使用 JAXB API 将哪个版本的类存储在持久性(读取:xml)中?
对我来说,存储类版本似乎很方便——就像在标准 java 序列化机制中完成的那样(我的意思是 serialVersionUID),并且即使在不同版本的情况下也提供将 xml 映射到类上的功能(例如,添加关于类版本的 XmlAdapter 信息存储在 xml 中)。默认情况下,如果 xml 和运行时中的类版本不同 - 抛出 InvalidClassException。
示例: 我们有类 Test 如下:
@XmlRootElement
@XmlAccessorType(value = XmlAccessType.FIELD)
public class Test {
private Long time;
private Test () {};
}
假设时间是以毫秒为单位的 UNIX 时间。
此代码已在生产环境中发布,并且此类已作为 xml 保存在数据库中。 下个版本表明使用Long作为时间表示不是很好的选择,它被改为Date:
@XmlRootElement
@XmlAccessorType(value = XmlAccessType.FIELD)
public class Test {
private Date time;
private Test () {};
}
现在有两种方法 - 迁移持久数据或编写将处理 Long time 并将其应用于 Date 时间的 xml 适配器。
如果我们选择第二种方式,如果 JAXB API 提供存储在 xml 中的类版本(假设没有在 class= 0 版本中指定类版本)并且我们显式添加新版本的类(通过注释或通过静态字段):
@XmlRootElement
@XmlAccessorType(value = XmlAccessType.FIELD)
@XmlClassVersion(value = 1)
public class Test {
private Date time;
private Test () {};
}
或
@XmlRootElement
@XmlAccessorType(value = XmlAccessType.FIELD)
public class Test {
private static final long xmlSerialVersionUID = 1;
private Date time;
private Test () {};
}
JAXB 会提供如下 XmlAdapter:
public abstract class XmlAdapter<ValueType,BoundType> {
protected XmlAdapter() {}
public abstract BoundType unmarshal(ValueType v, long classVersion) throws Exception;
public abstract ValueType marshal(BoundType v, long classVersion) throws Exception;
}
为了支持多个版本,当然,我们需要实现这样的适配器并显式处理不同的版本。 显然,JAXB 会在 xml 中添加关于类的特殊信息,并在最新的类版本上生成 xml。
注意:上面示例的要点是,我们在持久性中同时有 2 种不同的类表示,但仍然可以将它们映射到运行时中可用的类版本。
【问题讨论】:
标签: java xml-serialization jaxb xml-deserialization