简体   繁体   English

在同一Java对象上进行不同的XML映射/绑定

[英]distinct XML mapping/binding on the same Java object

I have a Java application interoperable with several others information systems 我有一个Java应用程序可与其他几个信息系统互操作

A same object could be mapped in differents XML files according to the information system targeted 根据目标信息系统,可以在不同的XML文件中映射相同的对象

My question is : Is there a Java solution to perform serveral XML mapping/binding on the same object 我的问题是:是否有Java解决方案在同一对象上执行多个XML映射/绑定

Somthing similar to Bean Validation groups that enable to validate an object with differents validation profile 与Bean Validation组类似的东西,可以使用不同的验证配置文件验证对象

In a JAXB style it could be something like that for instance: 在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;

    //...
}

and then 接着

    // 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);

may be it's possible to do such a thing with JAXB but I don't find out 也许可以用JAXB做这样的事情,但我没有发现


Edit 编辑

The response of @Martin Serrano give me some clues to optimize things with JAXB. @Martin Serrano的回应给了我一些用JAXB优化事物的线索。

An abstract class to rule them all: 一个抽象类来统治它们:

@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 + "}";
    }
}

And concretes classes that do the mapping: 并且混合了执行映射的类:

A class Person for the default mapping: 默认映射的类Person

@XmlRootElement
public class Person extends APerson {

    public Person() {
    }

    public Person(APerson p) {
        super(p);
    }

    @Override
    public String getLastname() {
        return lastname;
    }
}

And other classes for alternate mapping: 以及其他用于替代映射的类:

@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;
    }
}

And to test : 并测试:

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;
    }

}

as a result : 结果是 :

<?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}

That the best solution I found to have distinct mappings and to avoid code duplication, so we just have to implements the getters with the mapping. 我发现最好的解决方案有不同的映射并避免代码重复,因此我们只需要使用映射实现getter。

Let's see if it's working on a much bigger problem! 让我们看看它是否正在解决一个更大的问题!

But although it's a much better than having 3 disinct classes, it's still not 3 mappings on the same class... 但是虽然它比3个删除类要好得多,但它仍然不是同一类的3个映射...

The simplest way to do something like this would be to use different facades for each system. 做这样的事情的最简单方法是为每个系统使用不同的外观。 This would allow you to change the way JAXB de/serializes the objects. 这将允许您更改JAXB de / serialize对象的方式。 It would also allow you to do other transformations and adapting depending on the systems in question. 它还允许您根据相关系统进行其他转换和调整。 The base Person class would have your default serialization and each system could use the facade appropriate for it if necessary. 基本Person类将具有您的默认序列化,并且每个系统可以在必要时使用适合它的外观。 This is basically the approach outlined in the unofficial jaxb guide on mapping interfaces . 这基本上是关于映射接口的非官方jaxb指南中概述的方法。

Such facades could be registered for each system allowing you to keep system specific profiles out of the code of each of the core types. 可以为每个系统注册这样的外观,允许您将系统特定的配置文件保留在每个核心类型的代码之外。

Using your example, the core interface would be: 使用您的示例,核心接口将是:

@XmlRootElement(name="person")
public interface Person {
  @XmlElement(name = "lastName")
  private String lastName;
}

Then for System1 you would have: 然后对于System1,您将拥有:

@XmlRootElement(name="individual")
public class Individual implements Person {
}

Another system might have: 另一个系统可能有:

@XmlRootElement(name="human")
public class Human implements Person {
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM