Models
Table of contents
- Overview
- Defining a model
- Reading and writing attributes
- Mass-assignment
- Persistence shortcuts
- BaseModel contract
Overview
Every domain object in Jaloquent extends Model, which extends BaseModel. A model holds its state in an internal HashMap<String, Object> called attributes and delegates all persistence to a ModelRepository.
BaseModel ← id, getStoragePath(), toMap(), fromMap()
└── Model ← attributes map, get/set, fill/update, relations, save/delete/find
└── YourModel ← typed accessors, relation methods
Defining a model
import com.github.ezframework.jaloquent.model.Model;
public class Player extends Model {
public Player(String id) {
super(id);
}
// Typed accessor — getAs handles Integer ↔ Long ↔ String coercion
public String getName() {
return getAs("name", String.class, "");
}
public void setName(String name) {
set("name", name);
}
public int getCoins() {
return getAs("coins", Integer.class, 0);
}
public void setCoins(int coins) {
set("coins", coins);
}
}
The
idattribute is stored separately from the attribute map. Readingget("id")and writingset("id", value)both route throughgetId()/setId()automatically.
Reading and writing attributes
set(key, value) and get(key)
player.set("name", "Alice");
Object raw = player.get("name"); // returns Object
getAs(key, Class<T>) — type-coercing read
getAs performs automatic coercion between compatible types so models stay robust against the type differences between JDBC drivers, JSON deserializers, and in-memory stores.
// Returns Integer even if the store returned a Long
int coins = player.getAs("coins", Integer.class, 0);
// Returns String even if the stored value is an Integer
String level = player.getAs("level", String.class, "1");
Supported coercions:
| Stored type | Requested type | Result |
|---|---|---|
Long | Integer | longValue.intValue() |
Integer | Long | intValue.longValue() |
Integer / Long | String | String.valueOf(v) |
String | same | direct cast |
| any | same | direct cast |
attributes()
Returns an unmodifiable snapshot of the attribute map:
Map<String, Object> attrs = player.attributes();
toMap() and fromMap(Map)
Used internally for persistence but also useful for serialization:
// Serialize (e.g., to send over HTTP)
Map<String, Object> data = player.toMap();
// Deserialize (e.g., after loading from a store)
player.fromMap(data);
Mass-assignment
Jaloquent provides two modes of mass-assignment to protect against over-posting vulnerabilities.
fill(Map) — permissive mode
Applies every key from the map unless the key is guarded. If no fillable set is declared, all non-guarded keys are accepted.
player.setGuarded("isAdmin"); // block this key
// "name" and "coins" are applied; "isAdmin" is silently dropped
player.fill(Map.of("name", "Bob", "coins", 100, "isAdmin", true));
update(Map) — strict mode
Applies only keys that are explicitly declared via setFillable. If no fillable set has been declared, update() is a safe no-op.
player.setFillable("name", "coins"); // explicit allowlist
// Only "name" and "coins" are applied; everything else is dropped
player.update(Map.of("name", "Bob", "coins", 100, "role", "admin"));
id is always block-listed
Both fill() and update() will never apply an "id" key, regardless of fillable or guarded declarations.
Declaring fillable and guarded keys
// Only "name" and "coins" may be mass-assigned via update()
setFillable("name", "coins");
// Additional keys blocked from fill() even if fillable is empty
setGuarded("isAdmin", "role");
| Method | Returns |
|---|---|
getFillable() | Unmodifiable Set<String> |
getGuarded() | Unmodifiable Set<String> |
Prefer
update()in web or API handlers where you forward user-supplied maps directly to a model — it provides strict field-level control.
Persistence shortcuts
These convenience methods delegate directly to the given repository. See Repositories for the full persistence API including bulk operations, querying, and transactions.
save(repo)
Upserts the model and returns this for chaining (delegates to ModelRepository.save()):
player.setName("Alice").save(repo); // chained
// or
player.save(repo);
delete(repo)
Deletes the model by its current id:
player.delete(repo);
Model.find(repo, id) — static helper
Player player = Model.find(repo, "some-uuid"); // null if not found
BaseModel contract
Model inherits from BaseModel, which defines:
| Method | Description |
|---|---|
getId() | Return the primary key string |
setId(String) | Update the primary key |
getStoragePath(String prefix) | Returns prefix/id (or bare id when prefix is blank) |
toMap() | Abstract — serialize to flat map |
fromMap(Map) | Abstract — populate from flat map |
The storage path is used by flat-map DataStore implementations to locate records. When a TableRegistry entry exists for the prefix, the SQL path is used instead.