2012-07-06 116 views
0

我想marshall java.lang.Exception,但沒有成功。這裏是我的代碼 -如何使用JAXB Marshaller編組java.lang.Exception?

import java.io.File; 
import javax.xml.bind.JAXBContext; 
import javax.xml.bind.JAXBException; 
import javax.xml.bind.Marshaller; 

public class JAXBTester 
{ 
    public static void main(String[] args) throws Exception 
    { 
     TestReport report = new TestReport(); 
     report.setReportLog("Tests successful."); 

     File file = new File("TestReport.xml"); 
     JAXBContext jaxbContext = JAXBContext.newInstance(TestReport.class); 
     Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); 

     jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     jaxbMarshaller.marshal(report, file); 
    } 
} 

這是我想馬歇爾類 -

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

@XmlRootElement 
public class TestReport 
{ 
    private String reportLog; 
    private Exception exception; 

    @XmlElement 
    public void setReportLog(String reportLog) { this.reportLog = reportLog; } 

    public String getReportLog() { return reportLog; } 

    @XmlElement 
    public void setException(Exception exception) { this.exception = exception; } 

    public Exception getException() { return exception; } 

} 

我得到下面的異常 -

Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions 
java.lang.StackTraceElement does not have a no-arg default constructor. 
    this problem is related to the following location: 
     at java.lang.StackTraceElement 
     at public java.lang.StackTraceElement[] java.lang.Throwable.getStackTrace() 
     at java.lang.Throwable 
     at java.lang.Exception 
     at public java.lang.Exception TestReport.getException() 
     at TestReport 

    at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91) 
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:451) 
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:283) 
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:126) 
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1142) 
    at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:130) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:248) 
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:235) 
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:445) 
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:637) 
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584) 
    at JAXBTester.main(JAXBTester.java:14) 

這是因爲我想馬歇爾的Java。 lang.Exception。如何解決這個問題呢?

+0

參見[這個問題](http://stackoverflow.com/questions/1241551/how-do-you-serialize-an-找到exception-subclass-in-jaxb)來解決類似問題。 – Pyranja 2012-07-06 21:12:09

+0

@Pyranja,我以前見過那個。它是java.lang.Exception的子類。 – CodeBlue 2012-07-06 21:13:15

+3

確實如此,但您也可以將解決方案應用於Exception本身的序列化。問題是,由於缺少無參數構造函數(它是StackElement),Throwable類(所有異常的父類)的一部分無法序列化。爲了避免這種情況,你必須從序列化中排除堆棧元素。鏈接的問題顯示瞭如何做到這一點,因爲您無法修改Throwable類本身。 – Pyranja 2012-07-06 21:15:51

回答

1

還有其他方式可以做到這一點,比如評論者引用的方法。但這裏的另一種方式......

Throwable類的Java(的Exception超)爲java.io.Serializable感序列化。這意味着你可以將它寫入字節流,然後從這些字節中重新組合。 (這可能是您的應用程序可能有Throwable寫得不好的非序列化的子類。如果是這樣的話,以下將無法正常工作。)

所以要對付這種一種方式是編寫一個序列化自定義適配器Throwable(或Exception)轉換爲字節。在XML中,您會看到這些字節的十六進制。然後在接收端,您可以取消序列化,然後與您開始使用的Throwable(完全相同)複製。

這種方式的不好之處在於,異常在XML中是不可讀的。好的部分是它非常簡單。在您TestReport類,把這個註解你的Exception消氣:

@XmlJavaTypeAdapter(ThrowableAdapter.class) 
public Exception getException() { return exception; } 

public void setException(Exception exception) { this.exception = exception; } 

然後這個適配器類添加到您的項目:

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 

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

public class ThrowableAdapter extends XmlAdapter<String, Throwable> { 
    private HexBinaryAdapter hexAdapter = new HexBinaryAdapter(); 

    @Override 
    public String marshal(Throwable v) throws Exception { 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     ObjectOutputStream oos = new ObjectOutputStream(baos); 
     oos.writeObject(v); 
     oos.close(); 
     byte[] serializedBytes = baos.toByteArray(); 
     return hexAdapter.marshal(serializedBytes); 
    } 

    @Override 
    public Throwable unmarshal(String v) throws Exception { 
     byte[] serializedBytes = hexAdapter.unmarshal(v); 
     ByteArrayInputStream bais = new ByteArrayInputStream(serializedBytes); 
     ObjectInputStream ois = new ObjectInputStream(bais); 
     Throwable result = (Throwable) ois.readObject(); 
     return result; 
    } 
} 

那麼你的XML將包含類似這樣的元素:

<exception>AED...</exception> 

除了代替...,你會看到一個巨大的十六進制字符串。當它不在另一邊編組時,它就像原文一樣。

+0

如果傳輸完整的異常對象非常重要,那麼這是更好的解決方案。太好了! – Pyranja 2012-07-06 22:09:05

+0

不幸的是,如果你的異常封裝了一個不可序列化的對象,這個解決方案就不能工作。 – Mouna 2014-06-03 15:05:12

0

你使用JRE 1.7嗎?如果我使用隨JRE發佈的JAXB版本,則不會收到此異常。但是,如果我明確包含JAXB v 2.1.7,我會遇到這個問題。因此,我建議從類路徑中刪除所有jaxb實例,並使用Java運行時中包含的jaxb實例。

JRE 6似乎使用2.1.x,而JRE 7 2.2.x可能正確處理了Throwable實現中的更改。

包含在JDK的JAXB版本可以運行

<JDK_HOME>/bin/xjc -version