2013-04-22 47 views
1

我有以下類,我希望能夠基於一個接口動態地生成xml,更改實現...是可能的...我已經嘗試過一點點運氣...JaxB marhsalling使用接口

@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與父母真正知道實現?

回答

4

注意:我是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); 

} 

地址

import javax.xml.bind.annotation.XmlType; 

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

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

} 

下面是返回接口的具體impls工廠方法。這些是在解散操作期間將建造的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

爲了得到這個演示工作,你需要指定莫西爲您的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 

演示代碼

在演示代碼下面我們通過接口的任意實施編組。

演示

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>