0

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 をマーシャリングしようとしているからです。この問題を解決するには?

4

2 に答える 2

1

コメンターが参照した方法など、他の方法もあります。しかし、ここに別の方法があります...

JavaのThrowableクラス ( のスーパークラスException) は、 の意味でシリアライズ可能ですjava.io.Serializable。これは、バイトストリームに書き込んでから、後でそれらのバイトから再構成できることを意味します。(あなたのアプリケーションが、不適切に書かれたシリアル化不可能な のサブクラスを持っている可能性がありますThrowable。その場合、以下は機能しません。)

したがって、これに対処する 1 つの方法は、Throwable(またはException) をバイトにシリアル化するカスタム アダプターを作成することです。XML では、これらのバイトの 16 進数が表示されます。次に、受信側でシリアル化を解除してから、最初に使用した (の正確なレプリカ) を操作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>

ただし、代わりに...巨大な 16 進文字列が表示されます。反対側でマーシャリングを解除すると、元のようになります。

于 2012-07-06T21:37:28.503 に答える
0

JRE 1.7 を使用していますか? JRE で配布されている JAXB バージョンを使用すると、この例外は発生しません。ただし、JAXB v. 2.1.7 を明示的に含めると、この問題が発生します。したがって、クラスパスからすべての jaxb インスタンスを取り除き、Java ランタイムに含まれているインスタンスを使用することをお勧めします。

JRE 6 は 2.1.x を使用しているようですが、JRE 7 2.2.x はおそらく Throwable 実装の変更を正しく処理します。

JDK に含まれている JAXB のバージョンは、次のコマンドを実行して確認できます。

<JDK_HOME>/bin/xjc -version
于 2013-01-23T15:39:43.827 に答える