2

I got THIS class which is obviously mutable for every instance I create, but I want to know if there´s some kind of wrapper (or something) to make just ONE specific object of THIS class immutable. e.g Collections.unmodifiableList(beanList).

class Animal {
    private String name;
    private String commentary;

    public Animal(String nombre, String comentario) {
        this.name = nombre;
        this.commentary = comentario;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Animal animal = (Animal) o;
        return Objects.equals(name, animal.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

    public String getName() {
        return name;
    }

    public String getCommentary() {
        return commentary;
    }

    public void setCommentary(String commentary) {
        this.commentary = commentary;
    }

    public void setName(String name) {
        this.name = name;
    }
}
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
CBit
  • 53
  • 6
  • There would be no generic way to do it unless you make one for this specific class. This is because it's not possible to know which methods of the class are doing the mutation. – Swapan Pramanick Aug 22 '20 at 21:45

1 Answers1

6

The only way I am aware of is to instantiate it and override the methods that are able to modify the particular instance:

Animal animal = new Animal("name", "commentary") {

    @Override
    public void setCommentary(String commentary) {
        throw new UnsupportedOperationException("The Animal is immutable");
    }

    @Override
    public void setName(String name) {
        throw new UnsupportedOperationException("The Animal is immutable");
    }
};

This also satisfied the condition that only one specific instance of the class has a special behavior.


If you need more of them, create a wrapping class that acts as a decorator (isn't exactly). Do not forget to make the class as final otherwise you would be able to override its method in the way I described above and its immutability might break.

Animal animal = new ImmutableAnimal(new Animal("name", "commentary"));
final class ImmutableAnimal extends Animal {

    public ImmutableAnimal(Animal animal) {
        super(animal.getName(), animal.getCommentary());
    }

    @Override
    public void setCommentary(String commentary) {
        throw new UnsupportedOperationException("The Animal is immutable");
    }

    @Override
    public void setName(String name) {
        throw new UnsupportedOperationException("The Animal is immutable");
    }
}
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • 1
    It's strange to throw an `IllegalArgumentException`. –  Aug 22 '20 at 23:36
  • `Collections.unmodifiableList(beanList)` returns an unmodifiable list, but modifying `beanList` also modifies the list. The object returned by `new ImmutableAnimal(anAnmial)` is not changed even if you change `anAnimal`. –  Aug 22 '20 at 23:56
  • @saka1029: It was a first runtime exception in my mind. Now I feel UnsupportedOperationException would be more suitable. Does it change the quality of the answer? – Nikolas Charalambidis Aug 23 '20 at 07:49