Uma maneira de obter isso é fazer a minha class Person herdar de PersistentBean.
Só que concordo que heranca nesse caso não cai muito bem, pois estou misturando meus objetos sagrados com infra de persistencia. As pessoas fazem isso direto com as anotacoes de JPA/Hibernate, mas não é o objetivo do tópico entrar nesse mérito.
Então temos o problema clássico dos proxies em Java.
Pensei em fazer isso com um wrapper.
Person p = new Person();
PersistentBean<Person> bean = new PersistentBean<Person>(p);
Para acessar o objeto:
p.bean().getUsername();
p.bean().whateverHere();
// e quando eu quero persistir...
p.save();
p.update();
// etc.
O que vcs acham?
Para resumir tenho 4 opcões:
1 - Ignorar isso e quando quiser persistir um bean eu faco session.update(bean);
2 - Deixo de ser fresco e herdo de PersistentBean
3 - Uso CGLIB (seria uma bazooka para matar mosca?)
Particularmente prefiro evitar isso (cglib, aop) em Java por ser um overhead desnecessário NESTE tipo de cenário… então EU faria a entidade implementar uma interface com os métodos e injetar a implementação ou passar pelo construtor (dessa entidade).
Bem legal o seu approach. Deixei passar a opcao de composicao que é bem melhor que heranca nesse caso.
No meu caso ficaria assim:
public class Person implements PersistentBean {
BeanSession session;
public Person(BeanSession session) {
this.session = session;
}
public boolean update() {
session.update(this);
}
}
Não quero ter que fazer uma Collection para cada objeto, o seu PersonCollection.
Única desvantagem que vejo nisso é que vc continua atrelando o seu objeto a camada de persistencia, fazendo ele implementar a interface PersistentBean, o que é melhor que heranca com certeza. Mas esse desejo do Java de desacoplamento total talvez seja uma vontade desnecessária.
Então acho que fica assim:
Se quer desacoplamento total, faz session.update(person) por fora.
Se quer que o seu objeto tenha essa funcionalidade, usa composicao + interfaces.
Então, concordo contigo sobre ser muito xiita em relação a “desacoplamento total”, mas na medida do possível, eu acho bacana. Usei o termo “collections” justamente para não tender o tópico para Domain-Driven Design, mas já que estou comentando: tendo uma interface de negócio (não necessariamente uma por entidade, mas talvez uma por raiz) você consegue um belo desacoplamento entre o negócio e a infra-estrutura. A implementação dessa interface pouco vai importar.
Considere o uso de DI (via AOP, visto que não é comum ter entidades gerenciadas), pois seria bem legal injetar esse cara na entidade.
Injetar esse carinha via setter me parece a melhor alternativa, pois vc não quer construir um Person passando um BeanSession toda hora.
E eu sempre faco injecão por reflection, ou seja, sem necessidade de uma interface setBeanSession. Uma das primeiras coisas que o Mentawai mudou em relacao ao WebWork foi a necessidade daquelas interfaces SessionAware, XXXXXAware. No comeco eu injetava até em campo private, mas depois abandonei essa maluquice.
Só que ter que implementar a interface PersistentBean em tudo que é entidade é não rola, então estou usando composicao mais delegacao.
public clas Person implements PersistentBean {
private PersistentBean delegate = null;
public void setBeanSession(BeanSession session) {
this.delegate = new BasePersistentBean(this, session);
}
// delega tudo
public void insert() {
delegate.insert();
}
// ...
}
Estou me forcando a usar delegacao ao inves de heranca.
public class BasePersistentBean implements PersistentBean {
private final BeanSession session;
private final Object bean;
public BasePersistentBean(Object bean, BeanSession session) {
this.bean = bean;
this.session = session;
}
@Override
public void insert() {
session.insert(bean);
}
@Override
public boolean load() {
return session.load(bean);
}
@Override
public boolean update() {
return session.update(bean) == 1;
}
@Override
public boolean updateAll() {
return session.update(bean, false) == 1;
}
@Override
public boolean delete() {
return session.delete(bean);
}
}