PersistP is a simple library for loading properties files into Java objects and vice versa. It supports one-to-many relationships with lazy loading.
Make your class extend Entity
and use the @Prop
annotation on each field that you
want to be persisted.
public class Book extends Entity {
@Key String id;
@Prop String title;
@Prop double price;
@Prop @Temporal("yyyy/MM/dd") Date published;
@Prop("sellCount") int sold;
// Needed when loading from a file
public Book() {
}
public Book(String id, String title, double price, Date published) {
this.id = id;
this.title = title;
this.price = price;
this.published = published;
}
}
Notes:
- Use
@Prop("foo")
to bind a field to a property namedfoo
. The default property name is the same as the field name. - Use
@Key
to specify the unique primary key for this entity. This key is required and is used in the naming of the file. You can also add@Prop
if you want the key to be stored as a property within the file. - Use the
@Temporal
annotation on any Date specifying the format.
EntityMap<Book> books = EntityMap.instance(Book.class, new File("*.properties"));
Or,
EntityMap<Book> books = EntityMap.instance(Book.class, "*.properties");
Each file matching pattern *.properties
represents an Entity.
The part of the file path matching *
is the key.
Book book = books.get("book1");
The file book1.properties
is loaded into the Java object book
, where book1
is the key.
Book book = new Book("Book 2", 19.99, new Date());
book.saveTo(books);
The book is now stored in the file book2.properties
where book2
is the key, and is also added to the books
EntityMap.
book.sold++;
book.save();
book.delete();
The associated properties file is deleted and the book is removed from the books
EntityMap.
It is possible to override the delete
method if you wish to do more upon deletion.
public class Book extends Entity {
@FPattern("authors/*.property") Map<String, Author> authors;
...
}
Under the hood, an EntityMap
is injected into the authors
field. Every
author matching the pattern authors/*.property
is loaded into the map.
Notice that the map is not a property and is not annotated with @Prop
.
This is because it is a complete map without ordering, so no additional
information needs to be stored about which items to include and in what order
to include them.
new Author(1, "Author 1").saveTo(authors);
new Author(2, "Author 2").saveTo(authors);
These two lines result in the creation of two files authors/1.properties
and
authors/2.properties
which are added to the authors
map.
authors.get("1").delete();
This deletes the author with key "1".
A book has a list of authors:
public class Book extends Entity {
@FPattern("authors/*.property") Map<String, Author> authorsMap;
@Prop @FPattern("authors/*.property") List<Author> authors;
...
}
This associates the Java field authors
containing a list of Author
entities
to the property author
containing a comma-separated list of keys. Each entity
in the list is loaded from a file matching the pattern authors/*.property
where
*
is replaced by the key. The pattern is relative to the directory of the file
of the enclosing entity (e.g. relative to the parent directory of book1.properties
).
The Author
class MUST have a field annotated with @Key
, and optionally may
have a field annotated with @BackRef
which will be filled with a reference
to the parent book entity:
public class Author extends Entity {
@Key int id;
@Prop String name;
@BackRef Book book;
public Author() {
}
public Author(int id, String name) {
this.id = id;
this.name = name;
}
}
Note: Not every file matching the pattern authors/*.property
is loaded
into the list. Only keys appearing in the author
property in book1.properties
are loaded.
New entities can only be saved to the filesystem via an EntityMap
. Saved
entities can then be added to a list. Modifications to the list property,
as with modifications to any other property, must be followed by a call
to save()
on the entity containing that property.
Author author1 = new Author(1, "Author 1");
Author author2 = new Author(2, "Author 2");
author1.saveTo(book.authorsMap);
author2.saveTo(book.authorsMap);
book.authors.add(author1);
book.authors.add(author2);
book.save();
The first 4 lines write the files authors/1.properties
and
authors/2.properties
. The last 3 updates the file book1.properties
with
the property authors=1,2
whose value is a comma-separate list of the keys of
the authors in the list. You MUST call book.save()
after modifying the book's
list, otherwise the changes to the authors
property will not be stored.
Deleting an author involves first removing it from the list and then deleting it from the map:
book.authors.remove(author1);
book.save(); // do this first to avoid a dangling reference
author1.delete();
The first 2 lines write the new list to book1.properties
represented by the
property authors=2
. The last line deletes authors/1.properties
and removes
it from the authorsMap
EntityMap.
To reduce the memory footprint, list and map elements are not loaded into memory until accessed, and soft references allow elements to be reclaimed from memory by the garbage collector if the remaining available memory is too low.
An Entity
subclass may override the load()
and save()
methods to to load
and save complex properties that can't be automatically managed by PersistP's
annotations. Properties can be manually read and written via the following
methods inherited Entity
methods:
protected final String getProperty(String key)
protected final String getProperty(String key, String def)
protected final void setProperty(String key, String value)
protected final void removeProperty(String key)