我有以下类,我希望能够基于一个接口动态生成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;
}
}
我希望车辆的marshlling产生以下输出:
<vehicles>
<types>
<car>
..car specific elements
</car>
<motorbike>
.. mototrbike specific elements
<motorbike>
</types>
</vehicles>
车辆类无法了解实现,或者哪些存在...它只知道接口,这里我真正用作标记接口..允许我在运行时填充具有不同实现的列表。
无论如何我可以让jaxb将输出呈现为xml而父母真的知道这些实现吗?
答案 0 :(得分:5)
注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。
以下内容不适用于JAXB参考实现,但可以与EclipseLink JAXB(MOXy)一起使用。
JAVA模型
下面是一个表示为接口的简单域模型。我们将使用@XmlType
注释指定工厂类来创建这些接口的具体impl。这将需要满足解组(参见: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);
}
<强>地址强>
import javax.xml.bind.annotation.XmlType;
@XmlType(factoryClass=Factory.class, factoryMethod="createAddress")
public interface Address {
String getStreet();
void setStreet(String street);
}
<强>工厂强>
下面是返回接口的具体impls的工厂方法。这些是在解组操作期间建立的动力。为了防止需要真正的类,我将使用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;
}
}
}
}
的 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
DEMO CODE
在下面的演示代码中,我们传递了要编组的接口的任意实现。
<强>演示强>
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);
}
}
<强>输出强>
以下是运行演示代码的输出:
<?xml version="1.0" encoding="UTF-8"?>
<customer>
<name>Jane Doe</name>
<address>
<street>123 A Street</street>
</address>
</customer>