2012-07-06 118 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