Отличное сопоставление / привязка XML для одного и того же объекта Java
У меня есть приложение Java, совместимое с несколькими другими информационными системами
Один и тот же объект может быть отображен в разных XML-файлах в соответствии с целевой информационной системой.
Мой вопрос: есть ли решение Java для выполнения общего сопоставления / связывания XML с одним и тем же объектом?
Что-то похожее на группы Bean Validation, которые позволяют проверять объект с другим профилем проверки
В стиле JAXB это может быть что-то вроде этого, например:
// pseudocode
@XmlRootElement(name="person", , profile="profile1")
@XmlRootElement(name="individual", profile="profile2")
@XmlRootElement(name="human", profile="profile3")
public class Person {
@XmlElement(name = "lastName", profile="profile1")
@XmlElement(name = "surname", profile="profile2")
@XmlElement(name = "famillyName", profile="profile3")
private String lastName;
//...
}
а потом
// pseudocode
File file = new File("C:\\file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller("profile1");
jaxbMarshaller.marshal(person, file);
//...
File file = new File("C:\\file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller("profile1");
Person person = (Person) jaxbUnmarshaller.unmarshal(file);
может быть, это возможно сделать с JAXB, но я не узнаю
редактировать
Ответ @Martin Serrano дает мне некоторые подсказки, чтобы оптимизировать вещи с JAXB.
Абстрактный класс, чтобы управлять ими всеми:
@XmlTransient
public abstract class APerson {
protected String lastname;
public APerson() {
}
public APerson(APerson p) {
lastname = p.lastname;
}
public abstract String getLastname();
public void setLastname(String lastname) {
this.lastname = lastname;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{" + lastname + "}";
}
}
И конкретные классы, которые делают отображение:
Класс Person
для отображения по умолчанию:
@XmlRootElement
public class Person extends APerson {
public Person() {
}
public Person(APerson p) {
super(p);
}
@Override
public String getLastname() {
return lastname;
}
}
И другие классы для альтернативного отображения:
@XmlRootElement
public class Human extends APerson {
public Human() {
}
public Human(APerson p) {
super(p);
}
@Override
@XmlElement(name = "famillyName")
public String getLastname() {
return lastname;
}
}
@XmlRootElement
public class Individual extends APerson{
public Individual() {
}
public Individual(APerson p) {
super(p);
}
@Override
@XmlElement(name = "surname")
public String getLastname() {
return lastname;
}
}
И чтобы проверить:
public class Main {
public static void main(String[] args) throws Exception {
Person person = new Person();
person.setLastname("Doe");
String fileName = "person.xml";
marshal(person, fileName);
person = unmarshal(Person.class, fileName);
System.out.println(person);
fileName = "human.xml";
Human human = new Human(person);
marshal(human, fileName);
human = unmarshal(Human.class, fileName);
System.out.println(human);
person = new Person(human);
System.out.println(person);
fileName = "individual.xml";
Individual individual = new Individual(person);
marshal(individual, fileName);
individual = unmarshal(Individual.class, fileName);
System.out.println(individual);
person = new Person(individual);
System.out.println(person);
}
private static <P extends APerson> void marshal(P person, String fileName) throws JAXBException {
File file = new File(fileName);
JAXBContext context = JAXBContext.newInstance(person.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(person, file);
marshaller.marshal(person, System.out);
}
private static <P extends APerson> P unmarshal(Class<P> cl, String fileName) throws JAXBException {
File file = new File(fileName);
JAXBContext context = JAXBContext.newInstance(cl);
Unmarshaller unmarshaller = context.createUnmarshaller();
P person = (P) unmarshaller.unmarshal(file);
return person;
}
}
в следствии:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<lastname>Doe</lastname>
</person>
Person{Doe}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<human>
<famillyName>Doe</famillyName>
</human>
Human{Doe}
Person{Doe}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<individual>
<surname>Doe</surname>
</individual>
Individual{Doe}
Person{Doe}
Это лучшее решение, которое я нашел, чтобы иметь четкие отображения и избежать дублирования кода, поэтому нам просто нужно реализовать методы получения с отображением.
Давайте посмотрим, работает ли это над гораздо большей проблемой!
Но хотя это намного лучше, чем иметь 3 разных класса, это все же не 3 сопоставления в одном классе...
1 ответ
Самый простой способ сделать что-то подобное - использовать разные фасады для каждой системы. Это позволит вам изменить способ, которым JAXB де / сериализует объекты. Это также позволит вам выполнять другие преобразования и адаптацию в зависимости от рассматриваемых систем. База Person
Класс будет иметь сериализацию по умолчанию, и каждая система при необходимости может использовать соответствующий ей фасад. Это в основном подход, изложенный в неофициальном руководстве по jaxb по отображению интерфейсов.
Такие фасады могут быть зарегистрированы для каждой системы, что позволяет вам исключить профили системы из кода каждого из основных типов.
Используя ваш пример, основной интерфейс будет:
@XmlRootElement(name="person")
public interface Person {
@XmlElement(name = "lastName")
private String lastName;
}
Тогда для System1 у вас будет:
@XmlRootElement(name="individual")
public class Individual implements Person {
}
Другая система может иметь:
@XmlRootElement(name="human")
public class Human implements Person {
}