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