javafx and serializability

2020-05-02 16:49发布

In the old AWT libraries, the Point class and the Color class were serializable. Neither is in JavaFX. I would like to save an array list of Drawables to a file; here is the interface

import javafx.scene.canvas.GraphicsContext;

public interface Drawable
{
    public void draw(GraphicsContext g);
}

When I attempt to to this, I get bombarded by NotSerializableExceptons. What is the best alternate course of action? All of my drawables know their color and size.

1条回答
霸刀☆藐视天下
2楼-- · 2020-05-02 17:33

Use a custom serializable form and serialize the data you need. E.g.

import javafx.scene.canvas.GraphicsContext ;
import javafx.scene.paint.Color ;
import javafx.geometry.Rectangle2D;
import java.io.Serializable ;
import java.io.ObjectInputStream ;
import java.io.ObjectOutputStream ;
import java.io.IOException ;

public class DrawableRect implements Drawable, Serializable {

    private transient Color color ;
    private transient Rectangle2D bounds ;

    public DrawableRect(Color color, Rectangle2D bounds) {
        this.color = color ;
        this.bounds = bounds ;
    }

    @Override
    public void draw(GraphicsContext g) {
        g.setFill(color);
        g.fillRect(bounds.getMinX(), bounds.getMinY(), bounds.getWidth(), bounds.getHeight());
    }

    private void writeObject(ObjectOutputStream s) throws IOException {
        s.defaultWriteObject();
        // write color:
        s.writeDouble(color.getRed());
        s.writeDouble(color.getGreen());
        s.writeDouble(color.getBlue());
        s.writeDouble(color.getOpacity());

        // write bounds:
        s.writeDouble(bounds.getMinX());
        s.writeDouble(bounds.getMinY());
        s.writeDouble(bounds.getWidth());
        s.writeDouble(bounds.getHeight());
    }

    private void readObject(ObjectInputStream s)
            throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        double r = s.readDouble();
        double g = s.readDouble();
        double b = s.readDouble();
        double opacity = s.readDouble();

        color = new Color(r,g,b,opacity);

        double x = s.readDouble();
        double y = s.readDouble();
        double w = s.readDouble();
        double h = s.readDouble();

        bounds = new Rectangle2D(x,y,w,h);
    }
}

If you have fields that are serializable (or primitive types), you don't mark them transient, and the defaultReadObject and defaultWriteObject will handle them. If you have fields that are not serializable, mark them transient and serialize the data in a form that can be serialized as in the example.

Obviously, since you have multiple implementations of this interface which may all need this functionality, it might benefit you to create a helper class with some static methods:

public class DrawableIO {

    public static void writeColor(Color color, ObjectOutputStream s) throws IOException {
        s.writeDouble(color.getRed());
        s.writeDouble(color.getGreen());
        s.writeDouble(color.getBlue());
        s.writeDouble(color.getOpacity());
    }

    public static Color readColor(ObectInputStream s) throws IOException {
        double r = s.readDouble();
        double g = s.readDouble();
        double b = s.readDouble();
        double opacity = s.readDouble();

        return new Color(r,g,b,opacity);
    }

    public static void writeBounds(Rectangle2D bounds, ObjectOutputStream s) throws IOException {
        s.writeDouble(bounds.getMinX());
        s.writeDouble(bounds.getMinY());
        s.writeDouble(bounds.getWidth());
        s.writeDouble(bounds.getHeight());
    }

    public static Rectangle2D readBounds(ObjectInputStream s)  throws IOException {
        double x = s.readDouble();
        double y = s.readDouble();
        double w = s.readDouble();
        double h = s.readDouble();

        return new Rectangle2D(x,y,w,h);
    }
}

and then of course the methods in your Drawable implementations reduce to something like

private void writeObject(ObjectOutputStream s) throws IOException {
    s.defaultWriteObject();
    DrawableIO.writeColor(color, s);
    DrawableIO.writeBounds(bounds, s);
}

private void readObject(ObjectInputStream s)
        throws IOException, ClassNotFoundException {
    s.defaultReadObject();

    color = DrawableIO.readColor(s);
    bounds = DrawableIO.readBounds(s);
}
查看更多
登录 后发表回答