2012-06-18 53 views
7

我在網上找到了JAXB2 @XmlRegistry的一些例子,但沒有深入的教程討論使用@XmlRegistry@XmlElementDecl的概念,不知道它的一個概念通常沒有太多的探索。@XmlRegistry - 它是如何工作的?

反正這是我的問題,首先,我使用解組使用JAXB的XML一些示例類:

我試圖使用JAXB解組的主類 - Employee.java

package com.test.jaxb; 

import java.util.List; 

import javax.xml.bind.JAXBElement; 
import javax.xml.bind.annotation.XmlElementDecl; 
import javax.xml.bind.annotation.XmlRegistry; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.namespace.QName; 

import com.test.jaxb.dto.Address; 

@XmlRootElement 
public class Employee { 
    private int id; 
    private String name; 
    private String email; 

    private List<Address> addresses; 

    public int getId() { 
     return id; 
    } 
    public void setId(int id) { 
     this.id = id; 
    } 
    public String getName() { 
     return name; 
    } 
    public void setName(String name) { 
     this.name = name; 
    } 
    public String getEmail() { 
     return email; 
    } 
    public void setEmail(String email) { 
     this.email = email; 
    } 

    public List<Address> getAddresses() { 
     return addresses; 
    } 
    public void setAddresses(List<Address> addresses) { 
     this.addresses = addresses; 
    } 

    @SuppressWarnings("unused") 
    @XmlRegistry 
    public static class XMLObjectFactory { 
     @XmlElementDecl(scope = Employee.class, name= "id") 
     JAXBElement<String> createEmployeeId(String value) { 
      return new JAXBElement<String>(new QName("id"), String.class, "100"); 
     } 
     @XmlElementDecl(scope = Employee.class, name= "name") 
     JAXBElement<String> createName(String value) { 
      return new JAXBElement<String>(new QName("name"), String.class, "Fake Name"); 
     } 
     @XmlElementDecl(scope = Employee.class, name= "email") 
     JAXBElement<String> createEmail(String value) { 
      return new JAXBElement<String>(new QName("email"), String.class, value); 
     } 

     @XmlElementDecl(scope = Employee.class, name= "addresses") 
     JAXBElement<List> createAddresses(List value) { 
      return new JAXBElement<List>(new QName("addresses"), List.class, value); 
     } 
    } 
} 

子類 - Address.java

package com.test.jaxb.dto; 

import javax.xml.bind.JAXBElement; 
import javax.xml.bind.annotation.XmlElementDecl; 
import javax.xml.bind.annotation.XmlRegistry; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.namespace.QName; 

import com.test.jaxb.Employee; 

@XmlRootElement 
public class Address { 
    private String addressLine1; 
    private String addressLine2; 
    private String addressLine3; 
    public String getAddressLine1() { 
     return addressLine1; 
    } 
    public void setAddressLine1(String addressLine1) { 
     this.addressLine1 = addressLine1; 
    } 
    public String getAddressLine2() { 
     return addressLine2; 
    } 
    public void setAddressLine2(String addressLine2) { 
     this.addressLine2 = addressLine2; 
    } 
    public String getAddressLine3() { 
     return addressLine3; 
    } 
    public void setAddressLine3(String addressLine3) { 
     this.addressLine3 = addressLine3; 
    } 

    @SuppressWarnings("unused") 
    @XmlRegistry 
    private static class XMLObjectFactory { 
     @XmlElementDecl(scope = Employee.class, name= "addressLine1") 
     JAXBElement<String> createAddressLine1(String value) { 
      return new JAXBElement<String>(new QName("addressLine1"), String.class, value); 
     } 
     @XmlElementDecl(scope = Employee.class, name= "addressLine2") 
     JAXBElement<String> createAddressLine2(String value) { 
      return new JAXBElement<String>(new QName("addressLine2"), String.class, value); 
     } 
     @XmlElementDecl(scope = Employee.class, name= "addressLine3") 
     JAXBElement<String> createAddressLine3(String value) { 
      return new JAXBElement<String>(new QName("addressLine3"), String.class, value); 
     } 
    } 
} 

XML以解組 - employee.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<employee> 
    <id>1</id> 
    <name>Vaishali</name> 
    <email>[email protected]</email> 
    <addresses> 
     <address> 
      <addressLine1>300</addressLine1> 
      <addressLine2>Mumbai</addressLine2> 
      <addressLine3>India</addressLine3> 
     </address> 
     <address> 
      <addressLine1>301</addressLine1> 
      <addressLine2>Pune</addressLine2> 
      <addressLine3>India</addressLine3> 
     </address> 
    </addresses> 
</employee> 

解組代碼:

package com.test.jaxb; 

import java.io.FileReader; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Unmarshaller; 


public class ObjectFactoryTest { 
    public static void main(String[] args) throws Exception { 
     FileReader reader = new FileReader("resources/employee.xml"); 
     JAXBContext context = JAXBContext.newInstance(Employee.class); 
     Unmarshaller unmarshaller = context.createUnmarshaller(); 
     Object obj = unmarshaller.unmarshal(reader); 
     System.out.println(obj); 
    } 
} 

當我使用上面的代碼解編員工XML,地址列表沒有得到填充。由此產生的員工對象只有一個空白的地址列表。我的映射有什麼問題嗎?

爲了找出發生了什麼,並查看員工對象是否實際上是使用對象工廠(具有@XMLRegistry註釋)創建的,我在工廠方法中更改了id和name的值,但是它們沒有影響在輸出中,它告訴我JAXB實際上並沒有使用ObjectFactory,爲什麼?

我會不會這樣都錯了?任何幫助,將不勝感激。

回答

15

@XmlRegistry - 它是如何工作的?

@XmlRegistry用於標記具有@XmlElementDecl註釋的類。爲了讓您的JAXB實現處理此類,您需要確保它包含在用於引導JAXBContext的類列表中。這是不夠的,它是一個靜態內部類的域模型類中的一種:

JAXBContext context = JAXBContext.newInstance(Employee.class, Employee.XMLObjectFactory.class); 

@XmlElementDecl - 它是如何工作的?

如果字段/屬性的值將是JAXBElement那麼您需要利用@XmlElementDecl。甲JAXBElement捕獲與可以是有用的信息:

  • 元素名稱,這如果要映射到一個選擇的結構,其中多個元件具有相同的類型是必要的。如果元素名稱不對應於唯一類型,那麼您將無法對文檔進行往返。
  • JAXBElement可用於表示具有xsi:nil="true"的元素。

XmlObjectFactory

@XmlElementDecl還允許您指定一個範圍。我已經修改了你的模型發佈了一下。我已經介紹了一個XmlObjectFactory類,它有兩個@XmlElementDecl。兩者都指定名稱address。我已經利用了scope屬性,因此Employee類中的屬性@XmlElementDecl對應於Address類將被使用。

package forum11078850; 

import javax.xml.bind.JAXBElement; 
import javax.xml.bind.annotation.XmlElementDecl; 
import javax.xml.bind.annotation.XmlRegistry; 
import javax.xml.namespace.QName; 

@XmlRegistry 
public class XmlObjectFactory { 

    @XmlElementDecl(scope = Employee.class, name = "address") 
    JAXBElement<Address> createAddress(Address value) { 
     return new JAXBElement<Address>(new QName("address"), Address.class, value); 
    } 

    @XmlElementDecl(name = "address") 
    JAXBElement<String> createStringAddress(String value) { 
     return new JAXBElement<String>(new QName("address"), String.class, value); 
    } 

} 

僱員

@XmlElementRef註釋將導致屬性的值作爲對其根元素名稱匹配。可能的匹配將包括與@XmlRootElement@XmlElementDecl映射的類。

package forum11078850; 

import java.util.List; 

import javax.xml.bind.JAXBElement; 
import javax.xml.bind.annotation.*; 

@XmlRootElement 
@XmlType(propOrder = { "id", "name", "email", "addresses" }) 
public class Employee { 
    private int id; 
    private String name; 
    private String email; 

    private List<JAXBElement<Address>> addresses; 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public String getEmail() { 
     return email; 
    } 

    public void setEmail(String email) { 
     this.email = email; 
    } 

    @XmlElementWrapper 
    @XmlElementRef(name="address") 
    public List<JAXBElement<Address>> getAddresses() { 
     return addresses; 
    } 

    public void setAddresses(List<JAXBElement<Address>> addresses) { 
     this.addresses = addresses; 
    } 

} 

ObjectFactoryTest

package forum11078850; 

import java.io.FileReader; 
import javax.xml.bind.*; 

public class ObjectFactoryTest { 
    public static void main(String[] args) throws Exception { 
     FileReader reader = new FileReader("src/forum11078850/input.xml"); 
     JAXBContext context = JAXBContext.newInstance(Employee.class, XmlObjectFactory.class); 
     Unmarshaller unmarshaller = context.createUnmarshaller(); 
     Object obj = unmarshaller.unmarshal(reader); 

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

Address類和我原來的答覆input.xml可以用來運行這個例子。


原來的答案

我不知道你是如何嘗試使用@XmlRegistry,所以我會專注於您的文章的以下部分:

當我解編員工xml使用上面的代碼,地址列表 沒有得到填充。生成的員工對象只有一個空白的地址列表 。我的映射有什麼問題嗎?

Address對象列表被包裹在一個分組元素(addresses),所以你需要使用@XmlElementWrapper註解來映射這種使用情況。下面是一個完整的例子:

員工

package forum11078850; 

import java.util.List; 
import javax.xml.bind.annotation.*; 

@XmlRootElement 
@XmlType(propOrder = { "id", "name", "email", "addresses" }) 
public class Employee { 
    private int id; 
    private String name; 
    private String email; 

    private List<Address> addresses; 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public String getEmail() { 
     return email; 
    } 

    public void setEmail(String email) { 
     this.email = email; 
    } 

    @XmlElementWrapper 
    @XmlElement(name = "address") 
    public List<Address> getAddresses() { 
     return addresses; 
    } 

    public void setAddresses(List<Address> addresses) { 
     this.addresses = addresses; 
    } 

} 

地址

package forum11078850; 

public class Address { 
    private String addressLine1; 
    private String addressLine2; 
    private String addressLine3; 

    public String getAddressLine1() { 
     return addressLine1; 
    } 

    public void setAddressLine1(String addressLine1) { 
     this.addressLine1 = addressLine1; 
    } 

    public String getAddressLine2() { 
     return addressLine2; 
    } 

    public void setAddressLine2(String addressLine2) { 
     this.addressLine2 = addressLine2; 
    } 

    public String getAddressLine3() { 
     return addressLine3; 
    } 

    public void setAddressLine3(String addressLine3) { 
     this.addressLine3 = addressLine3; 
    } 

} 

ObjectFactoryTest

package forum11078850; 

import java.io.FileReader; 
import javax.xml.bind.*; 

public class ObjectFactoryTest { 
    public static void main(String[] args) throws Exception { 
     FileReader reader = new FileReader("src/forum11078850/input.xml"); 
     JAXBContext context = JAXBContext.newInstance(Employee.class); 
     Unmarshaller unmarshaller = context.createUnmarshaller(); 
     Object obj = unmarshaller.unmarshal(reader); 

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

的input.xml /輸出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<employee> 
    <id>1</id> 
    <name>Vaishali</name> 
    <email>[email protected]</email> 
    <addresses> 
     <address> 
      <addressLine1>300</addressLine1> 
      <addressLine2>Mumbai</addressLine2> 
      <addressLine3>India</addressLine3> 
     </address> 
     <address> 
      <addressLine1>301</addressLine1> 
      <addressLine2>Pune</addressLine2> 
      <addressLine3>India</addressLine3> 
     </address> 
    </addresses> 
</employee> 
+0

我發現了幾個'@XmlRegistry'的例子,就像我使用它一樣,看看[這裏](http://www.codezealot.org/archives/5)。我明白我可以使用'@XmlElementWrapper'來做到這一點。我的問題更多的是瞭解'@XmlRegistry'是什麼以及我可以用它做什麼。 AFAIK我應該能夠使用objectfactory(用'@XmlRegistry'註解)解組一個xml並將其轉換爲一個對象。如果不是,它用於什麼?我是否需要在某處註冊它才能使用它(就像我在我的例子中演示的那樣,我的對象工廠從未真正被JAXB使用過)? – gresdiplitude

+0

我的理解可能在這裏完全有缺陷的,但我認爲必須有應用類似的東西的一種方式「@XmlElementWrapper」到「@XmlRegistry」,因爲它的解組XML的另一種方式。沒有猜測的點我完全困惑@XmlRegistry如何工作! – gresdiplitude

+0

@Vaishali - 我已經更新了我的答案,包括一個例子利用'@ XmlRegistry'和'@ XmlElementDecl' –

-1

你必須帶一個地址列表對象。在該對象中,您將不得不添加包含像addressline1這樣的數據的對象。地址欄2等。

i.e. 
List addrObjList = new List(); 
addrObjList.add(object); // Bind an object containing data and add one by one 
+0

兩件事情,一個 - 不應該要求作爲地址類本身標註有@XmlRootElement並擁有自己的對象工廠,JAXB應該能夠自動做到這一點...和兩個 - 就像我在我的問題中提到的那樣,JAXB似乎根本沒有使用對象工廠,所以我對工廠方法所做的任何更改都不起作用。 – gresdiplitude

相關問題