2012-12-05 7 views
6

In Java macht die Serialisierung das Lesen und Schreiben von Objekten in Streams wirklich einfach. Zum Beispiel ist der folgende Code-Schnipsel meist alle es Objekte zu schreiben in einem Stream nimmt:Pfad zu problematischen nicht serialisierbaren Elementvariablen finden

ObjectOutputStream oos = ... //Initialize your output stream 
Object toWrite = ...   //Initialize what you want to write here 
oos.writeObject(toWrite); //Writes the object to the stream 
oos.flush(); 

Das funktioniert ganz gut, vorausgesetzt, dass toWrite ‚s-Klasse implementiert die Serializable Schnittstelle und dass alle toWrite‘ s Nicht- Mitgliedsvariablen sind auch Serializable. Mit anderen Worten, die gesamte Objekthierarchie, die Sie über die Referenz toWrite senden möchten, muss Serializable lauten. Angenommen, das einzige Problem mit diesem Code ist, dass etwas in toWrite nicht Serializable ist.

Wenn die Hierarchie nicht vollständig Serializable ist, löst der Aufruf oos.writeObject(toWrite) eine java.io.NotSerializableException. Dies ist alles in Ordnung und gut, außer dass die Ausnahme nicht alles gibt, was Sie brauchen, um das Problem schnell zu beheben. Es wird Ihnen sagen, welche Klasse nicht serialisiert werden konnte. Ihre Stack-Trace könnte wie folgt aussehen:

java.io.NotSerializableException: some.package.and.ClassIDidntExplicitlyReference 
    at java.io.ObjectOutputStream.writeObject0(Unknown Source) 
    ... 
    at my.package.MyClass.codeThatWroteTheOffendingObject(MyClass.java:###) 

Diese Art der Punkte, die Sie in der richtigen Richtung, aber in Fällen, die von toWrite verwiesen tiefe Objekthierarchien beinhalten, es ist nicht immer klar, wo die betreffende Klassenreferenz kam. Nehmen wir an, ich weise toWrite einer Instanz von MyClass zu, und meine Instanz MyClass hat eine Member Objektreferenz namens nonSerializableReference, die auf eine Instanz von ClassIDidntExplicitlyReference gesetzt wurde, die nicht Serializable ist. Ich möchte etwas sehen, wie die ausgedruckten folgenden:

my.package.MyClass.nonSerializableReference instanceof some.package.and.ClassIDidntExplicitlyReference 

Ich weiß, das Problem wahrscheinlich nicht eine schnelle Lösung hat, und wird wahrscheinlich beinhalten Reflexionen verwenden. Hat jemand hier auf SO das schon mal gemacht und wenn ja, hätten Sie etwas dagegen, Ihre Erkenntnisse zu teilen?

Antwort

landete ich mit bis Field und Modifier Klasse Spiegelung den Weg zu finden. Leider kann ich meinen Code nicht teilen (gegen Firmenrichtlinien), aber ich kann Ihnen meine Ausgabe zeigen. Klasse A hält eine Instanz von B, B eine Instanz von C hält, und C hält eine Instanz von D. All Serializable mit Ausnahme von D. I Depth-First-Search am Ende mit dem Pfad zu finden:

A.b -> 
    B.c -> 
    C.d instanceof class D 

Wenn ich Transienten mache, liefert die Suche keine Ergebnisse. Ziemlich cool!

+0

Sie möchten die Java Serialization-Implementierung ändern, suchen Sie nach anderen Implementierungen wie JBoss Serialization, vielleicht hat das Ihre Anfrage, oder senden Sie eine Anfrage auf Oracle Java-Community .... –

+0

Ich glaube nicht, dass Sie verstehen, was ich ' Ich frage nach. Ich möchte die Serialisierungsimplementierung nicht ändern, ich möchte einfach den Pfad von 'myObject' zu der Mitgliedsvariablen kennen, die das Problem verursacht hat. Danach würde ich entweder entscheiden, wie diese Elementvariable "Serializable" implementieren oder "transient" machen soll. * Diese * Entscheidung hängt völlig davon ab, was der Pfad zu der beleidigenden Variable sein wird. – CodeBlind

+0

'Es funktioniert auch nur, wenn Sie keine Serialisierungsschleifen haben': das ist nicht korrekt. Die Serialisierung bewältigt die zyklischen Objektdiagramme sehr gut. Siehe die Objektserialisierungsspezifikation. – EJP

Antwort

2

Dies ist eine seltsame Frage - Sie möchten zur Laufzeit feststellen, was Sie zur Kompilierzeit tun sollten. Theoretisch sollte der Pfad zu dem Objekt nicht von Bedeutung sein - Sie müssen die Objekte finden, die auf Dinge verweisen, die nicht serialisierbar sind, um Ihren Code zu reparieren.

Das heißt, Sie könnten einen einfachen rekursiven Tree-Crawler mit Reflektion schreiben. Das heißt, Sie könnten mit der Implementierung Ihres eigenen ObjectInputStream fortfahren, der die ankommenden Objekte protokolliert. Ich empfehle, einen Blick auf die source für weitere Details

+1

Einverstanden, es ist seltsam, aber manchmal ist es zur Compilierzeit nicht immer offensichtlich, was nicht serialisierbar sein könnte. Ich schreibe im Grunde ein verteiltes Computing-Framework, das von mehreren Entwicklern für die Verwendung einer sehr großen, komplexen, alten Codebasis portiert wird. Einige der Objekthierarchien, mit denen sie zu tun haben werden, sind sehr tief und der schnellste Weg, Serialisierungsprobleme zu finden, besteht darin, sie auszuführen und zu sehen, was passiert. Ich habe ein Protokollsystem, das weiß, wann NotSerializableExceptions auftreten, so dass es für das Drucken des Pfads zu Objekten verantwortlich ist, die die Ausnahmen verursachen. – CodeBlind

2

Ich hatte das gleiche Problem, und ich habe auch die Crawler-Sache, über die Sie gesprochen haben, implementiert.Wenn jemand in ihm immer noch interessiert ist, stellte ich den Code hier: A good way to find unserializable fields in Java

+0

Angesichts dessen, dass dies eine brauchbare Implementierung bietet (die ich gerade benutzt habe, danke!), Sollte dies wirklich die akzeptierte Antwort sein. –

4

Übergeben Sie die Flagge -Dsun.io.serialization.extendedDebugInfo=true der JVM und es sollte Ihnen die genau die Informationen, die Sie wollen, wenn ein NotSerializableException geworfen wird.

Verwandte Themen