2011-09-26 45 views
1

我有一個Web服務器響應xml數據和使用它的客戶端。 兩者共享相同的域代碼。其中一個域對象是這樣的:通過擴展它們在Jaxb生成的類上添加/覆蓋行爲

@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER) 
@XmlRootElement(name = "image") 
public class Image { 

    private String filename; 
    private ImageTypeEnum type; 

    @XmlElement(name = "imageUri") 
    public String getAbsoluteUri() { 
     // some complex computation 
     return uri; 
    } 
} 

當我嘗試解組服務器的響應到這個對象,因爲有對絕對URI沒有二傳手,我沒有imageUri在類。所以我向它是這樣的:

public class FEImage extends Image{ 
private String imageUri; 
    public String getAbsoluteUri() { 
     return imageUri; 
    } 
    public void setAbsoluteUri(String imageUri) { 
     this.imageUri = imageUri; 
    } 
} 

我的ObjectFactory

@XmlRegistry 
public class ObjectFactory { 
    public Image createImage(){ 
     return new FEImage(); 
    } 
} 

我的代碼來解組​​是在這裏:

JAXBContext context = JAXBContext.newInstance(ObjectFactory.class); 
Unmarshaller unmarshaller = context.createUnmarshaller(); 
unmarshaller.setProperty("com.sun.xml.bind.ObjectFactory",new ObjectFactory());   
((JAXBElement)unmarshaller.unmarshal((InputStream) response.getEntity())).getValue(); 

然而,setAbsoluteUri似乎並沒有被得到調用FEImage同時解組。當我在Image.java中添加虛擬setAbsoluteUri時,一切都按預期工作。

有人能告訴我如何幹淨地從Image.java延長?

回答

4

備註:我是EclipseLink JAXB (MOXy)的領導和JAXB 2 (JSR-222)專家組的成員。


甲JAXB實現不需要實例化對象時使用的ObjectFactory類。您可以配置實例可以使用@XmlType註釋通過工廠類來完成:

@XmlType(factoryClass=ObjectFactory.class, factoryMethod="createImage") 
public class Image { 

    private String filename; 
    private ImageTypeEnum type; 

    @XmlElement(name = "imageUri") 
    public String getAbsoluteUri() { 
     // some complex computation 
     return uri; 
    } 
} 

如果你做到上面,那麼你的JAXB實現將仍然使用Image類派生元數據,所以它不會解決你的問題。另一種方法是使用一個XmlAdapter這個用例:

更妙的是,當你的域對象上的屬性沒有一個二傳手,你可以告訴你 JAXB實現(EclipseLink MOXy,地鐵,阿帕奇JaxMe等)改爲使用@XmlAccessorType(XmlAccessType.FIELD)使用字段(實例變量)訪問:

@XmlAccessorType(XmlAccessType.FIELD) 
public class Image { 
} 

更新#1

如果你不能夠修改域對象,那麼你可能有興趣在莫西的外部化的元數據。該擴展提供了一種通過XML的方式,爲不能修改源的類提供JAXB元數據。

更多信息


更新#2 - 基於聊天的結果

圖片

下面是Image類,我會用這個例子的實現。對於getAbsoluteUri()複雜的計算我只需添加前綴「CDN」的文件名:

package forum7552310; 

import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER) 
@XmlRootElement(name = "image") 
public class Image { 

    private String filename; 
    private ImageTypeEnum type; 

    @XmlElement(name = "imageUri") 
    public String getAbsoluteUri() { 
     return "CDN" + filename; 
    } 

} 

binding.xml

下面是莫西約束力的文件我放在一起。在這個文件中我做了幾件事情:

  • 設置XmlAccessorTypeFIELD
  • 馬克絕對URI屬性爲XmlTransient,因爲我們將要代替映射filename領域。
  • 指定XmlAdapter將與filename字段一起使用。這是應用在getAbsoluteUri()方法中完成的邏輯。

 

<?xml version="1.0"?> 
<xml-bindings 
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" 
    package-name="forum7552310"> 
    <java-types> 
     <java-type name="Image" xml-accessor-type="FIELD"> 
      <java-attributes> 
       <xml-element java-attribute="filename" name="imageUri"> 
        <xml-java-type-adapter value="forum7552310.FileNameAdapter"/> 
       </xml-element> 
       <xml-transient java-attribute="absoluteUri"/> 
      </java-attributes> 
     </java-type> 
    </java-types> 
</xml-bindings> 

FileNameAdapter

下面是適用相同的名字算法作爲getAbsoluteUri()方法XmlAdapter的實現:

package forum7552310; 

import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class FileNameAdapter extends XmlAdapter<String, String> { 

    @Override 
    public String marshal(String string) throws Exception { 
     return "CDN" + string; 
    } 

    @Override 
    public String unmarshal(String adaptedString) throws Exception { 
     return adaptedString.substring(3); 
    } 

} 

演示

下面是演示代碼演示如何創建的JAXBContext時應用綁定文件:

package forum7552310; 

import java.io.File; 
import java.util.HashMap; 
import java.util.Map; 

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

import org.eclipse.persistence.jaxb.JAXBContextFactory; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     Map<String, Object> properties = new HashMap<String, Object>(1); 
     properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum7552310/binding.xml"); 
     JAXBContext jc = JAXBContext.newInstance(new Class[] {Image.class}, properties); 

     File xml = new File("src/forum7552310/input.xml"); 
     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     Image image = (Image) unmarshaller.unmarshal(xml); 

     System.out.println(image.getAbsoluteUri()); 

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

JAXB。性能

您需要包括一個名爲jaxb.properties在同一個包中的文件,內容如下爲您Image類:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

的input.xml

這裏是XML我用的輸入:

<?xml version="1.0" encoding="UTF-8"?> 
<image> 
    <imageUri>CDNURI</imageUri> 
</image> 

輸出

這裏是從運行演示代碼的輸出:

CDNURI 
<?xml version="1.0" encoding="UTF-8"?> 
<image> 
    <imageUri>CDNURI</imageUri> 
</image> 
+0

,因爲我沒有過Image.java控制可能是不可能的。這可以在FEImage.java上完成嗎?此外,請注意absoluteUri不是Image.java中的實例級字段。它在飛行中生成。 – Sam

+0

@Sam - 我在答案中增加了更多細節。 –

+0

謝謝,這看起來很有希望。我已經開始實現這個,但繼續運行到javax.xml.bind.JAXBException:不支持屬性「eclipselink-oxm-xml」。我在與FEImage.java相同的位置指定了jaxb.properties,它是com.example.fe.domain.image。我也試過把它放在上面一層,也放在類路徑中,但沒有用。任何提示? – Sam

相關問題