Sunday, June 15, 2014

Serialization Proxy Pattern example

There are books, which change your life immensely. One of such books is "Effective Java" by Joshua Bloch. Below you may find small experiment, which was inspired by Chapter 11 of this book - "Serialization".

Suppose that we have a class designed for inheritance, which is not Serializable itself, and has no parameterless constructor, like in this example:
public class CumbersomePoint {

    private String name;

    private double x;

    private double y;

    protected CumbersomePoint(double x, double y, String name) {
        this.x = x;
        this.y = y;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public double getX() {
        return x;
    }

    public double getY() {
        return y;
    }

    ...
}
Now when we extend this class, for example in following way:
public class ConvenientPoint extends CumbersomePoint implements Serializable {

    public ConvenientPoint(double x, double y, String name) {
        super(x, y, name);
    }

    ...
}
and try to serialize and then deserialize any of ConvenientPoint instances, we'll quickly encounter beautiful InvalidClassException, complaining that there is no valid constructor. Situation looks kinda hopeless, until you apply technique known as Serialization Proxy Pattern.

We will start by adding to the ConvenientPoint class following inner class:
private static class SerializationProxy implements Serializable {

        private String name;

        private double x;

        private double y;

        public SerializationProxy(ConvenientPoint point) {
            this.name = point.getName();
            this.x = point.getX();
            this.y = point.getY();
        }

        private Object readResolve() {
            return new ConvenientPoint(x, y, name);
        }

    }
The SerializationProxy class will represent the logical state of enclosing class instance. We will have to add also following method to ConvenientPoint class:
    private Object writeReplace() {
        return new SerializationProxy(this);
    }

Now when the ConvenientPoint instance will be serialized, it will nominate its replacement, thanks to writeReplace method - SerializationProxy instance will be serialized instead of ConvenientPoint.

From the other side, when SerializationProxy will be deserialized, readResolve method usage will nominate its replacement, being ConvenientPoint instance.

As you see, we've made ConvenientPoint serializable, regardless of missing parameterless constructor of non-serializable parent class.

One more remark, at the end of this post - if you want to protect against breaking class invariants, enforced by the constructor, you may add following method to class using Serialization Proxy Pattern (ConvenientPoint in our example): 
    private void readObject(ObjectInputStream stream) throws InvalidObjectException {
        throw new InvalidObjectException("Use Serialization Proxy instead.");
    }
It will prevent deserialization of the enclosing class.

Sunday, May 4, 2014

@OneToOne with shared primary key, revisited :)

Long time ago, I wrote a post @OneToOne with shared primary key. Today I would like to return to this problem, with solution based on @MapsId annotation introduced in JPA 2.0

Again we have two entities: Primus and Secundus. Both entities have primary key using Long Java type. They are related 1-1, and Secundus should use the same primary key as Primus.
3 Years after my initial post they will look slightly different ;)
@Entity
@Table(name = "PRIMUS")
public class Primus {

    public static Primus newInstance() {
        Primus primus = new Primus();
        primus.secundus = new Secundus(primus);
        return primus;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "primus")
    private Secundus secundus;

    Primus() {
        super();
    }
    ...

}
Not much changed here, ;). Really important changes were made on the Secundus:
@Entity
@Table(name = "SECUNDUS")
public class Secundus {

    @Id
    private Long id;

    @JoinColumn(name = "ID")
    @OneToOne
    @MapsId
    private Primus primus;

    Secundus() {
        super();
    }

    public Secundus(Primus primus) {
        this();
        this.primus = primus;
    }
As you see, the @PrimaryKeyJoinColumn annotation is replaced with two annotations: @MapsId, which defines that Secundus identifier will be determined by Primus identifier, and @JoinColumn, specifying which column in SECUNDUS table will be used for joining. 

Nothing more is needed :) - JPA Provider should automatically ask Primus for its identifier, when persisting Secundus, as long as you take care of correct entities correlation, like in newInstance method of Primus.

Long live JPA 2.0+ ;) :)