JaxB marhsalling使用界面

use*_*190 1 jaxb2

我有以下课程,我希望能够基于接口,不断变化的实现动态生成xml。

@xmlRootElement
public class Vehicles {
   private String id;

   private List<VehicleType> types;


   .... various setters and getters...
   ... with annotated getters...

}

public interface VehicleType {
   public String getName();
}

public Car implements VehicleType {

    private String name;
    private String wheels;

    ...various constructors...

    @XmlElement
    public String getName() {
      return name;
    }

    @XmlElement
    public String getWheels() {
      return wheels;
    }

 }

public Motorbike implements VehicleType {

    private String name;
    private String exhaust;

    ...various constructors...

    @XmlElement
    public String getName() {
      return name;
    }

    @XmlElement
    public String getExhaust() {
      return exhaust;
    }

 }
Run Code Online (Sandbox Code Playgroud)

我希望车辆编组产生以下输出:

<vehicles>
   <types>
     <car>
        ..car specific elements
     </car>
     <motorbike>
        .. mototrbike specific elements
     <motorbike>
   </types>
</vehicles> 
Run Code Online (Sandbox Code Playgroud)

Vehicles类无法知道实现或存在的实现..它只知道接口,在这里我实际上将其用作标记接口..允许我在运行时填充具有不同实现的列表...

无论如何,我可以让jaxb将输出渲染为xml,而无需父母真正了解实现吗?

bdo*_*han 5

注意:我是EclipseLink JAXB(MOXy)的负责人,并且是JAXB(JSR-222)专家组的成员。

以下内容不适用于JAXB参考实现,但适用于EclipseLink JAXB(MOXy)。

JAVA模型

以下是表示为接口的简单域模型。我们将使用@XmlType批注指定一个工厂类来创建这些接口的具体实现。这将满足解组的要求(请参阅:http : //blog.bdoughan.com/2011/06/jaxb-and-factory-methods.html)。

顾客

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlType(
    propOrder={"name", "address"},
    factoryClass=Factory.class, 
    factoryMethod="createCustomer")
public interface Customer {

    String getName();
    void setName(String name);

    Address getAddress();
    void setAddress(Address address);

}
Run Code Online (Sandbox Code Playgroud)

地址

import javax.xml.bind.annotation.XmlType;

@XmlType(factoryClass=Factory.class, factoryMethod="createAddress")
public interface Address {

    String getStreet();
    void setStreet(String street);

}
Run Code Online (Sandbox Code Playgroud)

下面是返回接口具体含义的工厂方法。这些是将在非海警行动期间建立的干扰。为了避免需要真实的类,我将利用Proxy对象。

import java.lang.reflect.*;
import java.util.*;

public class Factory {

    public Customer createCustomer() {
        return createInstance(Customer.class);    }

    public Address createAddress() {
        return createInstance(Address.class);
    }

    private <T> T createInstance(Class<T> anInterface) {
        return (T) Proxy.newProxyInstance(anInterface.getClassLoader(), new Class[] {anInterface}, new InterfaceInvocationHandler());
    }

    private static class InterfaceInvocationHandler implements InvocationHandler {

        private Map<String, Object> values = new HashMap<String, Object>();

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();
            if(methodName.startsWith("get")) {
                return values.get(methodName.substring(3));
            } else {
                values.put(methodName.substring(3), args[0]);
                return null;
            }
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

jaxb.properties

要使此演示正常工作,您需要将MOXy指定为JAXB提供程序。这是通过jaxb.properties带有以下条目的文件完成的(请参阅:http : //blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Run Code Online (Sandbox Code Playgroud)

演示代码

在下面的演示代码中,我们传递了将要编组的接口的任意实现。

演示版

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Run Code Online (Sandbox Code Playgroud)

输出量

以下是运行演示代码的输出:

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        AddressImpl address = new AddressImpl();
        address.setStreet("123 A Street");

        CustomerImpl customer = new CustomerImpl();
        customer.setName("Jane Doe");
        customer.setAddress(address);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }

}
Run Code Online (Sandbox Code Playgroud)