Não sei se tem como fazer isso, mas minha situação é a seguinte. Imagine que existe uma classe Cliente que possui 0 ou vários dependentes. Essas classes são mutáveis e são persistidas em banco.
Em um dado momento, eu possuo uma instância da classe Cliente em mãos e eu preciso fazer um “filtro” e remover alguns dependentes da associação, mas somente em memória, e queria que essa instância fosse somente leitura, ou seja, o cara que receber essa instância só pode ler os dados, não pode dar um set em nada (nem que isso causasse um erro em runtime, como Collections.unmodifiableList faz com o add).
Um jeito de fazer isso seria ter um atributo na classe que definisse que a instância é read-only e em todos métodos que alterem o valor do objeto, verificar se esse atributo não está setado, mas não acho que seja uma boa solução! :lol:
Alguém já teve que fazer algo do tipo ou sabe uma maneira mais “elegante” e eficiente de fazer isso?
Vou tentar explicar a necessidade. Não é para bloquear a ação de usuários não. É o seguinte:
-Tenho um “blocão” (war) com várias interfaces web services (jar), sendo que cada interface dessa fala com um sistema externo diferente e consequentemente possuem um “contrato” diferente. Porém, todas elas recebem o objeto Cliente (que é genérico) e à partir dele cria seus objetos específicos.
-E tenho um bloco central (outro .war) que trabalha o objeto Cliente, persiste e faz os filtros necessários antes de enviá-lo para o bloco das interfaces.
Como tem bastante gente mexendo no projeto, preciso garantir que nenhuma interface vai querer atualizar e persistir o Cliente (que não está completo nesse ponto).
Espero que tenha sido pelo menos um pouco claro…rs
Por que você não adota a mesma solução do Collections.unmodifiableList e faz um proxy para sua classe?
Separe a interface da classe do Cliente, e passe a usar essa interface. Depois, crie uma classe chamada ClienteReadOnly, que receba um cliente, também implemente a interface, e que só delegue a classe cliente que ela encapsula os métodos getters. No caso dos setters, você pode lançar uma UnsupportedOperationException.
O uso fica igual ao com a Collections. Vamos supor que você tenha um ClienteImpl, mas queira retorna-lo como um cliente imodificável:
public Cliente getCliente() {
//Retornamos a versão read only desse cliente
return new ReadOnlyCliente(cliente);
}
Note que o ideal é que todos os seus métodos tenham como valor de retorno interface Cliente, não a classe concreta que implementa cliente. Assim você sempre terá poder de escolha sobre qual implementação concreta usar.
Comecei a fazer um teste com a abordagem do throw new UnsupportedOperationException() nos métodos set, mas tem um porém.
Se o cara tem uma instância do Cliente que é imutável (ClienteReadOnly) e pede pro Hibernate inserí-la, ela vai ser inserida na boa, pois pelo visto o Hibernate não chama o setId da classe.
Para resolver esse problema,estava pensando em colocar uma verifição nos métodos que insere e atualiza Cliente no banco. Essa verificação teria que checar se a instância do Cliente é ClienteImpl ou ClienteReadOnly. No primeiro caso deixaria fazer a operação, no segundo dispararia uma UnsupportedOperationException.
wellington.nogueira, não quero que alguém salve os dados “por acidente”, pois o meu problema é que os dados vão estar filtrados, ou seja, incompletos, e isso poderia causar uma inconsistência no BD e zicar com a lógica de negócio.
Uma opção seria criar uma interface ClienteImutavel a ser implementada pela classe Cliente que contivesse apenas as assinaturas getXXX() de cliente e você disponibilizasse essa interface para quem deve usá-lo como somente leitura.
Uma alternativa seria criar interfaces Cliente que herdasse ([size=7][color=green]extendesse[/color][/size]) ClienteImutavel e ClienteMutavel (que possuiria as assinaturas dos setXXX() ) e a classe Cliente atual fosse renomeada para ClienteImpl
Quando o sistema puder ler e escrever, você disponibilizaria a interface Cliente, qdo fosse apenas leitura, forneceria ClienteImutavel. Qdo o Cliente fosse somente escrita, forneceria ClienteMutavel
É um refactoring razoável mas impede erros relativos ao uso de um atributo de controle de leitura que pode ter um controle, as vezes, inviável se disseminado em diversos pontos.
[size=9][color=red]PS: Os nomes são apenas sugestões para clareza :P[/color]
Edit: extendesse não seria a palavra adequada. O certo é herdasse.[/size]
As vezes um grande refactoring previne problemas futuros muito maiores. Não sei qual a ide que usa, mas a do eclipse consegue ajudar muito nesse tipo de alteração.
A solução do ViniGodoy tbm é muito boa e, apesar de possivelmente causar um pouco de refactoring, internamente você passaria a tratar o objeto Cliente através de sua interface (ao invés de uma classe concreta que seria ClienteImpl) causando poucas mudanças.
Só não acho muito legal pois está deixando explícita a classe concreta (não que eu, as vezes não faça :oops: ), mas é uma solução simples.
Dúvida [size=9]de curioso[/size]: Você não quer que o dado seja gravado ou não quer dar margem a erros numa eventual recuperação dos mesmos?
E, em relação aos dados já existentes? (Se existirem). Não haverá mais chances de recuperação, se for uma parte que deve usar o objeto imutável?