deserializierungsproblem

Status
Nicht offen für weitere Antworten.
X

xtreme

Gast
Hallo,

ich bekomme eine Fehlermeldung beim Deserialisieren.

java.io.NotSerializableException: java.awt.BasicStroke

Ist ja ganz klar. Die Klasse implementiert nicht die Schnittstelle und kann daher nicht serialisiert werden. Mein Vorgehen sieht jetzt so aus, dass ich die Objekte mit dem Befehl
Code:
transient
kennzeichnen und sie nicht mit serialisiert werden. Daher muss ich sie aber nach dem deserialisieren wieder neu initialisieren oder etwa nicht?

Wie aber initialisiere ich solche Objekte beim Deserialisieren? In c# gibt es dazu eine weitere Schnittstelle namens
Code:
IDeserializationCallback
. Habe ich diese implementiert, kann ich die Methode
Code:
public void OnDeserialization(object sender)
überschreiben und dort alle Werte initialisieren.

Gibt es so etwas auch in Java oder wie muss ich das hier handhaben?
 
X

xtreme

Gast
OK bin nun etwas weiter. Habe gelesen, dass ich die Methode readObject implementieren sollte und dort alle Werte neu initialisiere. Das habe ich auch gemacht. In meinem Beispiel Serialisiere/Deserialisiere ich eine Liste mit Geometrien. Diese Geometrien haben nicht serialisierbare Attribute. Daher muss ich sie neu initialisieren. Allerdings bekomme ich jetzt eine NullPointerException. Die Methode readObject() wird bei mir aber auch gar nicht aufgerufen. Wie muss ich das richtig anstellen?

Hier mal nen Code-Ausschnitt:


Serialisierungsklasse:
Code:
public class Serializer {
    
        private List<Geometry> _saveList;
        private List<Geometry> _loadList;
        private String _dir;


        //Constructor-------------------------------------------------------------------------------------------

        public Serializer()
        {}
        
        //Methods-------------------------------------------------------------------------------------------

        public void saveObjects(List<Geometry> list, String directory)
        {
            _saveList = list;
            _dir = directory;

            serialize();
        }

        private void serialize()
        {
            try
            {
                FileOutputStream fs = new FileOutputStream(_dir, true);
                ObjectOutputStream os = new ObjectOutputStream(fs);             
                os.writeObject(_saveList);
                os.close();
            }
            catch (IOException e)
            {
                System.out.println("Serialize-Error: " + e);
            }
        }

        public List<Geometry> restoreObjects(String directory)
        {
            _dir = directory;

            deserialize();

            return _loadList;
        }

        private void deserialize()
        {
            try
            {
                FileInputStream fs = new FileInputStream(_dir);
                ObjectInputStream is = new ObjectInputStream(fs);
                _loadList = (List<Geometry>)is.readObject();
                is.close();
            }
            catch (Exception e)
            {
                System.out.println("Deserialize-Error: " + e);
            }
        }

}



Zu serialiserende Klasse:
Code:
public class Geometry implements Serializable, Cloneable{
    
        private transient BasicStroke _virtuellerHitPen = new BasicStroke(5);

        //Rahmen an/aus
        private transient boolean _selectionBorder = false;

        //Zeichenstift des Rahmens
        private transient BasicStroke _border;

        //Sichtbarkeit an/aus
        private boolean _visible = true;

        //Stiftfarbe
        private Color _color;

        //Stiftbreite
        private int _penWidth;

        //Zeichenstift
        private transient BasicStroke _pen;

        //Shape
        private Path2D.Double _path = new Path2D.Double();

        //Start- und Endpunkt des umschließenden Rechtecks
        private Point _start;
        private Point _end;

        //Breite und Höhe des umschließenden Rechtecks
        private int _width = 0;
        private int _height = 0;

        //Name des Objektes
        private String _name;


        //Die Methode wird nach dem Wiederherstellen aufgerufen und initialisiert alle benötigten Objekte
        private void readObject( ObjectInputStream ois ) throws IOException 
        { 
            try 
            { 
                ois.defaultReadObject();
                _pen = new BasicStroke(this._penWidth);
                _virtuellerHitPen  = new BasicStroke(5);
                _border = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1, new float[] { 10.0F, 20.0F}, 0);
                _selectionBorder = false;
                AddToPath();
            } 
            catch ( ClassNotFoundException e ) 
            { 
              throw new IOException( "No class found. HELP!!" ); 
            } 
        } 
}


Main-Code:
Code:
        List<Geometry> geometryObjectList = new Vector<Geometry>();
        List<Geometry> newGeometryObjectList = new Vector<Geometry>();
        
        Color lineColor = Color.BLACK;
        MyLine line = new MyLine(lineColor, 1);
        line.setName("line");
        line.SetStartPoint(new Point(1,1));
        line.SetEndPoint(new Point(10,10));
        
        
        Color recColor = Color.BLACK;
        Color recFillColor = Color.RED;
        MyRectangle rec = new MyRectangle(recFillColor, recColor, 1);
        rec.setName("rec");
        rec.SetStartPoint(new Point(1,1));
        rec.SetEndPoint(new Point(10,10));
        
        
        Color ellColor = Color.BLACK;
        Color ellFillColor = Color.RED;
        MyEllipse ell = new MyEllipse(ellFillColor, ellColor, 1);
        ell.setName("ell");
        ell.SetStartPoint(new Point(1,1));
        ell.SetEndPoint(new Point(10,10));
        
        Color ellColor1 = Color.BLUE;
        Color ellFillColor1 = Color.YELLOW;
        MyEllipse ell1 = new MyEllipse(ellFillColor1, ellColor1, 2);
        ell1.setName("ell1");
        ell1.SetStartPoint(new Point(1,1));
        ell1.SetEndPoint(new Point(10,10));
        
        
        geometryObjectList.add(line);
        geometryObjectList.add(rec);
        geometryObjectList.add(ell);
        geometryObjectList.add(ell1);

        //Serialize-Test
        Serializer s = new Serializer();
        s.saveObjects(geometryObjectList, "c:\\test.geo");
        
        newGeometryObjectList = s.restoreObjects("c:\\test.geo");
 
S

SlaterB

Gast
die Methode readObject() wird anscheinend nur bei den Subklassen wie MyLine aufgerufen, falls vorhanden,
du müßtest die Methode in Geometry schon protected machen und in allen Subklassen aufrufen,
nehme ich an..


-----

dein
> FileOutputStream fs = new FileOutputStream(_dir, true);

ist übrigens sehr übel, an einen ObjectOutputStream kann man eh nix ranhängen, wenn da einmal das Ende-Token drinsteht, dann wird das dahinter ignoriert,

und hat mich einige Minuten gekostet bis ich herausfand, warum da nach Codeänderungen das Verhalten gleich blieb,
es wurde immer das allererste uralte Objekt gelesen..
 
X

xtreme

Gast
Ich habe zwar in der Tat diese Subklassen, dort habe ich die Methode readObject aber gar nicht implementiert. Die Geomety-Klasse ist ja das Parent, reicht die Implementierung dort nicht aus?

Ferner frage ich mich, ob die Methode überhaupt so aufgerufen wird, denn ich habe nirgendwo nen Aufruf mit diesen Übergabeparamtern, oder handhabt der das selber?
 
X

xtreme

Gast
Oh ok, das Problem hat sich erledigt. Es lag genau an dem FileOutputStream und dem übergebenen boolean true. Nachdem ich das weggemacht habe, hat alles funktioniert.
 
X

xtreme

Gast
Mhm so ganz scheints daran doch nicht gelegen zu haben. Auf jeden Fall ging es jetzt auf einmal, nach dem ich mein NetBeans neugestartet hatte. Seltsam.

Zum Verständnis würde ich trotzdem gern wissen, wie das readObject(ObjectInputStream ois) in Geometry aufgerufen wird, wenn ich in meiner Deserialize Methode nur den Aufruf is.readObject(); getätigt hatte? Wird das selbstständig vom System durchgeführt?
 
S

SlaterB

Gast
was heißt schon vom System,
ist irgendwo im ObjectInputStream versteckt, genauer: in ObjectStreamClass,

Code:
			readObjectMethod = getPrivateMethod(cl, "readObject", 
			    new Class[] { ObjectInputStream.class }, 
			    Void.TYPE);


    /**
     * Returns non-static private method with given signature defined by given
     * class, or null if none found.  Access checks are disabled on the
     * returned method (if any).
     */
    private static Method getPrivateMethod(Class cl, String name, 
					   Class[] argTypes,
					   Class returnType)
    {
	try {
	    Method meth = cl.getDeclaredMethod(name, argTypes);
	    meth.setAccessible(true);
	    int mods = meth.getModifiers();
	    return ((meth.getReturnType() == returnType) &&
		    ((mods & Modifier.STATIC) == 0) &&
		    ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
	} catch (NoSuchMethodException ex) {
	    return null;
	}
    }


    /**
     * Invokes the readObject method of the represented serializable class.
     * Throws UnsupportedOperationException if this class descriptor is not
     * associated with a class, or if the class is externalizable,
     * non-serializable or does not define readObject.
     */
    void invokeReadObject(Object obj, ObjectInputStream in)
	throws ClassNotFoundException, IOException, 
	       UnsupportedOperationException
    {
	if (readObjectMethod != null) {
	    try {
		readObjectMethod.invoke(obj, new Object[]{ in });
	    } catch (InvocationTargetException ex) {
		Throwable th = ex.getTargetException();
		if (th instanceof ClassNotFoundException) {
		    throw (ClassNotFoundException) th;
		} else if (th instanceof IOException) {
		    throw (IOException) th;
		} else {
		    throwMiscException(th);
		}
	    } catch (IllegalAccessException ex) {
		// should not occur, as access checks have been suppressed
		throw new InternalError();
	    }
	} else {
	    throw new UnsupportedOperationException();
	}
    }
 
Status
Nicht offen für weitere Antworten.

Oben