Escaping colletcions and objects

Implementig Iterable:

public class CustomerRecords implements Iterable<Custormer> {

	List<Customer> records = new ArrayList<>();
	.
	.
	@Override
	public Iterator<Customer> iterator() {
		return records.values.iterator();
	}
}

 

Creating a copy of collection:

public class CustomerRecords {

	List<Customer> records = new ArrayList<>();
	.
	.
	public List<Customer> getRecords() {
		return new ArrayList<>(this.records);
	}	
}

 

Using Collentions.unmodifiable methods:

public class CustomerRecords {

	List<Customer> records = new ArrayList<>();
	.
	.
	public List<Customer> getRecords() {
		return Collections.unmodifiableList(records);
		//JAVA10+ ---JAVA8 also works in JAVA10+
		return List.copyOf(records);
	}	
}

 

In case getObject() creating an interface for Class without setters and return this will solve this problem:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

interface ReadOnlyBook {
    public String getTitle();
}

class Book implements ReadOnlyBook{

    private String title;

    public Book(String title) {
        this.title = title;
    }

    public Book(ReadOnlyBook book) {
        this.title = book.getTitle();
    }

    @Override
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

}

class Customer implements Cloneable{
    private String name;
    private Book book;

    public Customer(String name, Book book) {
        this.name = name;
        this.book = book;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Book getBook1() {
        return this.book;
    }

    public String getName() {
        return this.name;
    }

	//this is the right solution
    public ReadOnlyBook getBook2() {
        return new Book(this.book);
    }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", book=" + book +
                '}';
    }

    @Override
    protected Customer clone() throws CloneNotSupportedException {
        return (Customer) super.clone();
    }
}

public class App {

    public static void main(String... args) {
        App app = new App();
        app.start();
    }

    private void start() {
        Book myOrigBook = new Book("MyFirstBook");
        System.out.println("Created book:");
        System.out.println("myOrigBook: " + myOrigBook.getTitle());
        Customer customer = new Customer("vevo1", myOrigBook);

        Book book1 = customer.getBook1();
        book1.setTitle("My First Book");
        System.out.println("Used getBook1:");
        System.out.println("book1: " + book1.getTitle());
        System.out.println("myOrigBook: " + myOrigBook.getTitle());

        System.out.println("Used getBook2:");
        Book book2 = (Book)customer.getBook2();
        book2.setTitle("My Second Book");
        System.out.println("book2: " + book2.getTitle());
        System.out.println("myOrigBook: " + myOrigBook.getTitle());
    }
}

OUT:

Created book:
myOrigBook: MyFirstBook
Used getBook1:
book1: My First Book
myOrigBook: My First Book
Used getBook2:
book2: My Second Book
myOrigBook: My First Book

 

Testing collections:

import javax.crypto.spec.PSource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

interface ReadOnlyBook {
    public String getTitle();
}

class Book implements ReadOnlyBook{

    private String title;

    public Book(String title) {
        this.title = title;
    }

    public Book(ReadOnlyBook book) {
        this.title = book.getTitle();
    }

    @Override
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

}

class Customer implements Cloneable{
    private String name;
    private Book book;

    public Customer(String name, Book book) {
        this.name = name;
        this.book = book;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Book getBook1() {
        return this.book;
    }

    public String getName() {
        return this.name;
    }

    public ReadOnlyBook getBook2() {
        return new Book(this.book);
    }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", book=" + book +
                '}';
    }

    @Override
    protected Customer clone() throws CloneNotSupportedException {
        return (Customer) super.clone();
    }
}

public class App {

    public static void main(String... args) {
        App app = new App();
        app.start();
    }

    private void start() {
        List<Customer> firstCustomerList = new ArrayList<>();
        firstCustomerList.add(new Customer("First Customer",new Book("My First Book")));
        firstCustomerList.add(new Customer("Second Customer", new Book("My Second Book")));

        System.out.println("TestCase1 (ShallowCopy):");
        List<Customer> secondCustomerList = new ArrayList<>(firstCustomerList);
        secondCustomerList.get(1).setName("Hacked Customer1");
        firstCustomerList.forEach(System.out::println);

        System.out.println("TestCase2 (unmodifiableList):");
        List<Customer> thirdCustomerList = Collections.unmodifiableList(firstCustomerList);
        thirdCustomerList.get(1).setName("Hacked Customer2");
        firstCustomerList.forEach(System.out::println);

        System.out.println("TestCase3 (HardCopy):");

        List<Customer> fourhtCustomerList = new ArrayList<>();
        firstCustomerList.stream().forEach(v ->
        {
            try {
                fourhtCustomerList.add(v.clone());
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        });
        fourhtCustomerList.get(1).setName("Hacked Customer3");
        firstCustomerList.forEach(System.out::println);

        System.out.println("TestCase4 (unmodifiableList.remove):");
        thirdCustomerList.remove(0);

        System.out.println("The end");
    }

}

OUT:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.Collections$UnmodifiableList.remove(Collections.java:1319)
	at App.start(App.java:109)
	at App.main(App.java:76)
TestCase1 (ShallowCopy):
Customer{name='First Customer', book=Book@6d311334}
Customer{name='Hacked Customer1', book=Book@682a0b20}
TestCase2 (unmodifiableList):
Customer{name='First Customer', book=Book@6d311334}
Customer{name='Hacked Customer2', book=Book@682a0b20}
TestCase3 (HardCopy):
Customer{name='First Customer', book=Book@6d311334}
Customer{name='Hacked Customer2', book=Book@682a0b20}
TestCase4 (unmodifiableList.remove):

Process finished with exit code 1