1

I have a use case where I need to create a (mutable)object first, and at certain scenario I need to make it immutable(I don't wanna make it immutable upon creation). Is there a good way to achieve it? The requirement is to change it from mutable to immutable at some time, using final will not work.

4 Answers4

3

An object cannot be mutable and immutable at the same time. What you can do is you can have a method in your mutable object to return corresponding immutable object.

Here is an example of implementation of what I am saying.

class BasicMutable {
    private int i;

    public void setI(int i){
        this.i = i;
    }

    public void getI(){
        return i;
    }

    public BasicImmutable getImmutable(){
        return new BasicImmutable(this);
    }
}

Now create Immutable object

class BasicImmutable {
    private final i;

    BasicImmutable(BasicMutable bm){
        this.i = bm.i;
    }

    public void getI(){
        return i;
    }
}

You can also have a getMutable() method in BasicImmutable to get corresponding Mutable object.

afzalex
  • 8,598
  • 2
  • 34
  • 61
1

There are a number of libraries, that might do the job for you (I haven't used them myself).

https://github.com/verhas/immutator [1]

http://immutables.github.io [2]

Both libraries have their advantages and disadvantages.

[1] seems to be very lightweight and simple and allows you to define your own Query interface (which defines the immutable methods).

[2] seems to be very mature and feature complete and provides builders, JSON/GSON support etc.

Moritz Petersen
  • 12,902
  • 3
  • 38
  • 45
0
public class Mutable {
    private int member;

    public Mutable(int member) {
    this.member = member;
    }

    public int getMember() {
    return member;
    }

    public void setMember(int member) {
    this.member = member;
    }
}

public class ImmutableWrapper extends Mutable {

    private Mutable mutable;

    public ImmutableWrapper(Mutable mutable) {
    super(0); // dummy filling
    this.mutable = mutable;
    }

    @Override
    public int getMember() {
    return mutable.getMember();
    }

    @Override
    public void setMember(int member) {
    throw new UnsupportedOperationException();
    }
}


public static void main(final String[] args) {
    Mutable mutable = new Mutable(1);
    mutable = new ImmutableWrapper(mutable);
    mutable.getMember();
    try {
        mutable.setMember(8);
    } catch (final Exception e) {
        System.out.println(e);
    }
}

Output:

java.lang.UnsupportedOperationException

Laszlo Hirdi
  • 1,140
  • 12
  • 18
  • I don't like the coupling in this solution. If Mutable is updated to include a new mutating method then the developer has to know that they need to modify ImmutableWrapper as well – Stormcloud May 18 '16 at 07:44
  • I think this idea is similar to implementation of guava's immutableXXX right? we get unsupported exception so we can catch and handle it, cool! – Eugene z. Von May 18 '16 at 07:47
  • Yes, this is only to demonstrate the basic idea. For general solution a dynamic proxy can be used. – Laszlo Hirdi May 18 '16 at 07:49
-1

Shortly said: All members have to be declared final and all memeber types have to be immutable too.