JaxB marhsalling使用接口 [英] JaxB marhsalling using interfaces
问题描述
我有以下类,我希望能够基于一个接口动态生成xml,改变实现......这是可能的......我试过运气不好......
I have the following class, i want to be able to produce xml dynamically based ona an interface, with changing implementations... is that possible... i have tried with little luck...
@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到产生以下输出:
I want the marshlling of Vehicles to produce the following output:
<vehicles>
<types>
<car>
..car specific elements
</car>
<motorbike>
.. mototrbike specific elements
<motorbike>
</types>
</vehicles>
车辆类无法了解实现,或者存在哪些......它只知道接口,这里我真的用作标记界面..允许我在运行时填充具有不同实现的列表...
The vehicles class cannot know about the implementations, or which ones exist.. it only knows about the interface, which here im using as a marker interface really.. to allow me to populate a list with different implementations at runtime...
无论如何我可以得到jaxb是将输出呈现为xml,而父母确实知道实现?
Is there anyway i can get jaxb be to render the output as xml with out the parent really knowing about the implementations?
推荐答案
注意:我是 EclipseLink JAXB(MOXy) 的主管和 JAXB(JSR-222) 专家的成员group。
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
以下内容不适用于JAXB参考实现,但可以使用EclipseLink JAXB(MOXy)。
The following will not work with the JAXB reference implementation but will work with EclipseLink JAXB (MOXy).
JAVA模型
下面是一个表示为int的简单域模型erfaces。我们将使用 @XmlType
批注指定工厂类来创建这些接口的具体impl。这将需要满足解组(参见: http:// blog .bdoughan.com / 2011/06 / jaxb-and-factory-methods.html 。
Below is a simple domain model represented as interfaces. We will use the @XmlType
annotation to specify a factory class to create concrete impls of these interfaces. This will be required to satisfy unmarshalling (see: 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的工厂方法。这些是在解组操作期间建立的动力。为了防止需要真正的类,我将利用代理
对象。
Below is the factory method that returns concrete impls of the interfaces. These are the impls that will be built during an unmarshal operation. To prevent requiring real classes I will leverage Proxy
objects.
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 )
To get this demo to work you will need to specify MOXy as your JAXB provider. This is done via a jaxb.properties
file with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html)
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
DEMO CODE
在下面的演示代码中,我们通过了任意实现要编组的接口。
In the demo code below we pass an arbitrary implementation of the interfaces to be marshalled.
演示
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);
}
}
输出
以下是运行演示代码的输出:
Below is the output from running the demo code:
<?xml version="1.0" encoding="UTF-8"?>
<customer>
<name>Jane Doe</name>
<address>
<street>123 A Street</street>
</address>
</customer>
这篇关于JaxB marhsalling使用接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!