As far as you have many-to-many relationship you need to have some storage in order to store all data (something like database). And the best approach IMHO is make you lists transient and restore items from this storage when you are restoring your serialisable. If it is really database in your case you can use some in-memory cache in order to make it faster.
[EDIT]:
Here is alternative implementation with storage:
Storage.java:
public class Storage implements Serializable {
private final HashMap<Integer, Book> books;
private final HashMap<Integer, Author> authors;
public Storage() {
books = new HashMap<>();
authors = new HashMap<>();
}
public void addBook(Book book) {
books.put(book.ISPN, book);
}
public void removeBook(Book book) {
books.remove(book.ISPN);
}
public void addAuthor(Author author) {
authors.put(author.authorID, author);
}
public void removeAuthor(Author author) {
authors.remove(author.authorID);
}
public Author getAuthor(Integer authorId) {
return authors.get(authorId);
}
public Book getBook(Integer bookId) {
return books.get(bookId);
}
}
Book.java:
public class Book implements Serializable {
int ISPN;
String title;
String description;
int pageCount;
ArrayList<Integer> AuthorIds;
Storage storage;
public Book(Storage storage) {
this.storage = storage;
}
public void addAuthor(Author author) {
storage.addAuthor(author);
AuthorIds.add(author.authorID);
}
public List<Author> createAuthorsList() {
List<Author> authorList = new ArrayList<>();
for (Integer authorId : AuthorIds) {
authorList.add(storage.getAuthor(authorId));
}
return authorList;
}
}
Author.java:
public class Author {
int authorID;
String firstName;
String lastName;
ArrayList<Integer> bookIds;
Storage storage;
public Author(Storage storage) {
this.storage = storage;
}
public void addBook(Book book) {
storage.addBook(book);
bookIds.add(book.ISPN);
}
public List<Book> createBooksList() {
List<Book> bookList = new ArrayList<>();
for (Integer bookId : bookIds) {
bookList.add(storage.getBook(bookId));
}
return bookList;
}
}
The only one (but big) disadvantage of using this implementation, that after deserialisation you will have multiple instances of Storage
class with same data. It order to optimize this I would suggest you to make storage entries as transient members and serialize them separately.