Estava brincando um pouco com a versão 1.02 do Prevayler e surgiu a seguinte situação…
Depois de persistir alguns commandLogs tentei fazer algumas modificações na estrutura da entidadezinha q criei implementando Serializable…
Xiii…
Recovering system state...
Reading PrevalenceBase00000000000000000001.commandLog...
java.io.InvalidClassException: teste.entity.Produto; local class incompatible: stream classdesc serialVersionUID = -7229049240096558055, local class serialVersionUID = 7723610941337660017
Some commands might have been lost. Looking for the next file...
Reading PrevalenceBase00000000000000000002.commandLog...
java.io.InvalidClassException: teste.entity.Produto; local class incompatible: stream classdesc serialVersionUID = -7229049240096558055, local class serialVersionUID = 7723610941337660017
Some commands might have been lost. Looking for the next file...
Reading PrevalenceBase00000000000000000003.commandLog...
Tamanho da Lista de Produtos: 0
Reading PrevalenceBase00000000000000000004.commandLog...
Tamanho da Lista de Produtos: 0
Reading PrevalenceBase00000000000000000005.commandLog...
java.io.InvalidClassException: teste.entity.Produto; local class incompatible: stream classdesc serialVersionUID = -7229049240096558055, local class serialVersionUID = 7723610941337660017
Some commands might have been lost. Looking for the next file...
Reading PrevalenceBase00000000000000000006.commandLog...
Tamanho da Lista de Produtos: 0
Ótimo…
Então, criei uma classe Base que implementa Serializable e uma Child pra estendê-la…
E com a ajuda do Polimorfismo, não precisei perder aquilo q já estava salvo…Pronto!
Agora pergunto…
O Prevayler 2.0 tem alguma coisa pra minimização dos impactos da alteração dos Business Objects???
Qual é a melhor solução pra não ter problema com isso???
A solução temporaria q achei será q seria viável???
Já tiveram problemas com isso???
Versionamento de classes eh um porre, mesmo, e a melhor maneira que eu encontrei ateh hoje pra me livrar de dores de cabeca fortissimas nessas horas eh exportar o meu sistema pra um outro tipo de arquivo (XML eh uma boa pedida, geralmente), e reimportar depois que eu fiz as mudancas no .class.
Mas, em muitos casos, vc nao precisa ser tao radical assim: apenas coloque o campo serialVersionUID (leia a spec de serializacao) com uma versao certa, e tah blza
Mas pô, será que se no Prevayler eu tivesse uma “PrevalenceEntity”(HeHeHe!) que fosse manipulada pelos Commands e etc, aproveitando do polimorfismo não seria melhor???
Certo q seria uma classe q não implementaria nada, apenas implementaria Serializable, mas…acho q não teria problema mais com versionamento…
Teria porque alguma classe concreta acabaria tendo que ser serializada.
Existe alguns aproachs mais radicais que resolvem isso.
Vc divide seu objeto de negocio em 2: um de dados e outro de lógica, o de lógica nunca é serializado e o de dados nunca muda.
Algo +/- assim:
interface ClienteModel {
String getNome();
void setNome(String nome);
void processaPedido(Pedido pedido) throws FooException;
}
class ClienteData implements ClienteModel, Serializable {
transient ClienteLogic cliente;
String nome;
public ClienteData() {
cliente = ClienteFactory.getInstance().newInstance(this);
}
public String getNome() { return nome; }
public void setNome(String nome) { this.nome = nome; }
public void processaPedido(Pedido pedido) throws FooException {
cliente.processaPedido(pedido);
}
}
class ClienteLogic {
ClienteData cliente;
public Cliente(ClienteData cliente) { this.cliente = cliente; }
void processaPedido(Pedido pedido) throws FooException {
throw new RuntimeException("não deu certo "+cliente.nome);
}
}
A factory deixo como exercicio.
Dessa forma fica bem mais facil e claro o versionamento da tua classe sem depender do serialVersionUID.
O ruim disso é que vc fica com 1 tonelada de factories no sistema.
Até onde eu sei, o SerialVersionUID só muda quando a estrutura da classe muda (i.e. campos a mais ou a menos). Adicionar e remover métodos não muda nada.
Dessa forma, uma alteração da forma como o Diogenes descreveu ia acabar tendo que mexer na classe Model…
Ainda sou a favor do “SuperBean”:
public class SuperBean implements Serializable, InvocationHandler {
private Map map;
public Object invoke(Object proxy, Method m, Object[] args) {
if (m.getName().startsWith("get")) {
return map.get(m.getName().substring(3));
}
else if (m.getName().startsWith("is")) {
return map.get(m.getName().substring(2));
}
else if (m.getName().startsWith("set")) {
map.put(m.getName().substring(3), args[0]);
}
}
}
public interface Person {
public String getName();
public void setName(String name);
public String getDescription();
public void setDescription(String description);
}
public class PersistentFactory {
public Person createPerson() {
InvocationHandler h = new SuperBean(new HashMap());
return Proxy.newProxyClass(Person.class.getClassLoader(), new Class[]{Person.class, Serializable.class}, h);
}
}
Pra ser um super bean mesmo tem que implementar indexed properties e tal… mas se vc aumentar sua Person, não precisa fazer nada com o SuperBean, que sempre terá versão constante.
Claro que isso tudo é teoria e eu não tive tempo ainda de testar… e vc ainda tem que viver de factories. Ou vc pode usar o Pico (que em qtde de código dá na mesma).
Desculpe a ignorância Louds, mas realmente não entendí como uma alteração no meu cliente, como por exemplo a adição de um campo endereço, não mais afetaria a versão da minha classe com esse esquema de dividir o objeto em 2…
Hehehehe… essa vem da minha fixação atual pelo MetaLevel.
Bom, não tem nada de especial aí, só reflection na veia!
Precisa dar uma aprimorada, como o cv falou.
De qq maneira vc vai ficar preso a alugém que te dê a instância que vc quer, pq de forma alguma vc vai dar new Person() e vc tb não quer que o SuperBean implemente Person, senão perdeu a graça. Mas a idéia é exatamente essa. Pensa que vc decidiu então que todos os seus objetos prevalentes vão ser jogados num mapa:
public void setName(String name) {
map.put("name", name);
}
daí vc começa a achar que é muito trabalho fazer isso em todas as suas classes, e pensa num jeito meta de abstrair e ter tudo num lugar só, como manda o figurino.