Интересно, есть ли какая-либо поддержка различных версий класса в JAXB.
Мои мысли по этому поводу: xml - это своего рода объект персистентности класса (сериализованное значение), но объект класса может быть изменен в результате разработки (например, расширение функциональности). Есть ли способ узнать, какая версия класса хранится в постоянстве (читай: xml), используя только JAXB API?
Для меня кажется удобным хранить версию класса - как это сделано в стандартном механизме сериализации 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 () {};
}
Теперь есть два способа - либо перенести сохраненные данные, либо написать xml-адаптер, который будет обрабатывать Долгое время и применять его к дате.
Если мы выберем второй способ, было бы замечательно, если бы JAXB API предоставил версию класса, которая была сохранена в xml (при условии, что в классе = 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 разных представления класса в персистенции одновременно, но мы все равно можем сопоставить их с версией класса, доступной во время выполнения.