Search code examples
javamutable

How to safely publish a mutable object?


I don't want to do the deep copy way.

Say, I have a field of some mutable type, a x,y,z Coordinate for example. Occasionally, I need to expose this field to some viewers. And I want it be read-only. I remember reading something like a wrapper to do these kind of stuff, but I don't remember the details.

The x,y,z Coordinate example may be too simple because x,y,z are primitive type. So getX() always return a copy.

I want a general solution even if the x,y,z fields are of yet another mutable type.

Can anybody help?


EDIT:

public class Client
{

    public static final Holder holder = new Holder();


    public static void main(String[] args)
    {

        UserWrapper user = holder.getUser();
        System.out.println(user);               //UserWrapper{user=User{address=Address{street='street 101'}}}
        user.getAddress().setStreet("mars");    //UserWrapper{user=User{address=Address{street='mars'}}}
        System.out.println(user);

    }
}

public class Holder
{

    private User user;

    public Holder()
    {
        user = new User();
        Address address = new Address();
        address.setStreet("street 101");
        user.setAddress(address);
    }

    public UserWrapper getUser()
    {
        return new UserWrapper(user);
    }

}

public class User
{

    private Address address;

    public Address getAddress()
    {
        return address;
    }

    public void setAddress(Address address)
    {
        this.address = address;
    }
}

public class UserWrapper
{

    private User user;

    public UserWrapper(User user)
    {
        this.user = user;
    }

    public Address getAddress()
    {
        return user.getAddress();
    }
}

EDIT: credit to I don't know who(he deletes the answer), I find this link he mentioned in his original post very helpful.


Solution

  • The traditional ways:

    • deep copy - prevents mutations from impacting the client who is reading
    • immutable objects - instead of copying for the client, you copy to update and the client gets an old pointer reference.
    • customer iterator - you provide your own iterator / navigation interface, which is sensitive to a "version" field embedded with the data structure. Before visiting each element, it checks that the version has not been changed since the iterator was created (java collections does this).
    • strong synchronization - while a reader is reading, the reader holds a lock on the data structure preventing update. Generally a bad solution, but occasionally useful (included for completeness).
    • lazy copy - you construct an object that mostly references the original, but is triggered (as a listener) to the original, such that when a mutation is done on the original, you copy the pre-mutated value locally. This is like a lazy deep copy strategy.

    There's others, but this should get you started.