É possível realizar um CAST dinamicamente ?
Estou pensando fazer algo, como no exemplo abaixo:
((ProdutoUnicVO)produtoVO).setFlagEstoque("S")
O que iria variar seria a classe “ProdutoUnicVO”.
A chamada do método é realizada da seguinte forma:
Minha classe Service:
public Object consultarProdutoPorCodg(String codgProduto, Integer codgFilial) throws Exception
{
if(codgFilial == 1) {
return this.produtoDAO.consultarProdutoPorCodg(ProdutoUnicVO.class, codgProduto);
else
return this.produtoDAO.consultarProdutoPorCodg(ProdutoFamaVO.class, codgProduto);
}
Minha classe DAO:
[code]public Object consultarProdutoPorCodg(Class objClass, String codgProduto) throws Exception {
Object produtoVO = null;
try {
Criteria criteria = this.getSession().createCriteria(objClass);
criteria.add(Restrictions.eq("codgProduto", StringUtil.preencheDir(codgProduto, 15, ' ')));
produtoVO = criteria.uniqueResult();
if(((ProdutoUnicVO)produtoVO).setFlagEstoque("S")) {
((ProdutoUnicVO)produtoVO).setFlagEstoque("Sim");
} else {
((ProdutoUnicVO)produtoVO).setFlagEstoque("Não");
}
}
catch (Exception e) {
throw new Exception("Erro ao consultar produto por código: " + e.getClass().getName() + ": " + e.getMessage());
}
return produtoVO;
}[/code]
Veja que realizo um CAST utilizando a classe “ProdutoUnicVO”, funciona perfeitamente.
Mas gostaria que fosse possivel utilizar outras classes também, como ProdutoFamaVO, ProdutoUnimeVO, etc… sem a necessidade de ficar duplicando código.
em java 6 vc pode usar generics para dizer que a classe é de um certo tipo
antes disso vc smplesmente pode invocar o set via reflection
Se todas as classes ProdutoXxxVO compartilharem os mesmos métodos (setFlagEstoque() por exemplo) vc pode criar uma classe ProdutoVO que as classes ProdutoXxxVO extenderão… assim seu cast seria sempre pra ProdutoVO e nao para cada um dos milhoes de tipos de produtos que vc criar… mas caso eles nao compartilhem os mesmos métodos entao a solução seria usar reflection mesmo…
Cara, seu código tá meio feio hein…
“throws Exception”
“if(codgFilial == 1)”
“((ProdutoUnicVO)produtoVO).setFlagEstoque(“Sim”);”
victor.
Não é que o código esta feio, postei dessa forma para exemplificar meu problema.
“throws Exception” : Utilizo para passar o exeção pra frente, não faço o tratamento ali.
“if(codgFilial == 1)” : Utilizei apenas para exemplificar os tipos de parametros que posso utilizar, se for uma coisa faz isso, se for outra faz aquilo.
Cada classe ProdutoxxxVO esta mapeada para uma tabela no BDs, dependendo da empresa que o usuário estiver logado deverei utilizar um VO especifico, atualmente estou utilizando apenas ProdutoUnicVO, mas agora isso pode varear, não quero ficar duplicando classes, métodos por estar utilizando VOs diferentes, quero montar uma esqueminha genéricamente.
“((ProdutoUnicVO)produtoVO).setFlagEstoque(“Sim”);” : Coloquei dessa forma para exemplificar o meu problema.
produtoVO é do tipo Object, e não possui um método setFlagEstoque(""), então preciso fazer um CAST, utilizando “ProdutoUnicVO”, mas como o VO para consulta pode variar, esse CAST deve ser dinamicamente.
Mas esta complicado de fazer.
[quote=Heider Matos]
“((ProdutoUnicVO)produtoVO).setFlagEstoque(“Sim”);” : Coloquei dessa forma para exemplificar o meu problema.
produtoVO é do tipo Object, e não possui um método setFlagEstoque(""), então preciso fazer um CAST, utilizando “ProdutoUnicVO”, mas como o VO para consulta pode variar, esse CAST deve ser dinamicamente.
Mas esta complicado de fazer.[/quote]
Os metodos que que vc usará nesse DAO sao métodos diferentes que fazem coisas diferentes para cada VO é isso? Seria mais interessante vc mandar algum trecho de codigo com seu problema real… pq assim poderemos analisar as melhores opcoes… por esse codigo q vc mandou (pela impressao que dá) parece q o metodo setFlagEstoque será compartilhado para todos os produtos… se isso for verdade use a heranca como eu havia dito: vc passa todos os metodos comuns aos VOs para a classe ProdutoVO e depois extende dessa classe. seu cast na verdade seria somente uma conversao de um tipo mais especializado para um outro menos especializado, no caso o ProdutoVO.
É esse seu problema? Se nao for por favor explique melhor parar sabermos como te ajudar 
Ah esqueci de dizer, vc pode usar ainda uma classe abstrada ou uma interface… daria na mesma…
Seu problema:
Object produtoVO = null;
...
produtoVO = criteria.uniqueResult();
A primeira coisa a fazer:
ProdutoVO produtoVO = null;
...
produtoVO = (ProdutoVO) criteria.uniqueResult();
Com isso você já pode remover pelo menos dois terços dos casts e reduzir o problema.
andre2k2, essa solução que você postou me ajuda em partes.
Os meus VOs estão mapeado para tabelas de BDs, estou utilizando Hibernate.
Não tem como eu utilizar herança, por causa das annotations de cada VO, alguns métodos são diferentes tb.
O lance seria mudar apenas a classe utilizada no CAST.
victorwss, realizar um CAST utilizando uma classe especifica eu já faço, quero apenas mudar o CAST.
Mas esta complicado.
Quais são as heranças de ProdutoUnicVO e ProdutoFamaVO?
Esses VOs não possuem herança.
Mas teem atributos direferentes, consequentemente métodos diferentes.
Por exemplo ProdutoUnicVO, possui um atributo ProdutoSaldoUnicVO, como descrito abaixo:
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "b1_cod")
private ProdutoSaldoUnicVO produtoSaldoVO;
Em ProdutoFamaVO, já muda para ProdutoSaldoFamaVO, que é outro VO mapeado para outra tabala no BDs.
Você é de Cuiabá?
Você sabe fazer o CAST dinamicamente utilizando Reflection ?
[quote=Heider Matos]Esses VOs não possuem herança.
Mas teem atributos direferentes, consequentemente métodos diferentes.
Por exemplo ProdutoUnicVO, possui um atributo ProdutoSaldoUnicVO, como descrito abaixo:
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "b1_cod")
private ProdutoSaldoUnicVO produtoSaldoVO;
Em ProdutoFamaVO, já muda para ProdutoSaldoFamaVO, que é outro VO mapeado para outra tabala no BDs.
Você é de Cuiabá?
Você sabe fazer o CAST dinamicamente utilizando Reflection ?[/quote]
Acho bom vc dar uma olhada melhor no projeto… to vendo q a arquitetura dele ta falhando em alguns pontos… produto saldo esta me parecendo ser a mesma coisa mas pra classes diferentes… de uma analisada se vc nao pode melhorar a orientacao a objeto da sua arquitetura… use interfaces… herança… enfim tudo q a OO pode te dar… as vezes repensar seu projeto pode te abrir muitas portas sem precisar de coisas mirabolantes como reflection!!!
Sim, sou de Cuiabá. O andre2k2 também é e está a cerca de 3 metros de distância de mim.
Sim, eu sei fazer um cast dinamicamente com reflection. Mas não acho que isso não vai te ajudar, porque os métodos do seu tipo dinâmico não serão conhecidos.
if(((ProdutoUnicVO)produtoVO).setFlagEstoque("S")) {
((ProdutoUnicVO)produtoVO).setFlagEstoque("Sim");
} else {
((ProdutoUnicVO)produtoVO).setFlagEstoque("Não");
}
Estes métodos são comuns a ProdutoUnicVO e a ProdutoFamaVO ou só existem em um deles?
Tente escrever testes unitários para esse método e depois pense em generics.
Eu utilizo o padrão de DAO genérico para persistência de dados e bastante OO, rsrs…
Esta correta minha estrutura, o que me ferra é a base de dados que utilizo, não foi eu quem criei.
Utilizo um BDs dos sistema da MICROSIGA utilizado na empresa que trabalho.
Por exemplo quando o usuário realiza uma solicitação de produto(Papel A-4), esta solicitação lê uma tabela de BDs referente a empresa que o usuário esta lotado.
Se for a empresa UNIC, lê a tabela sb1010.
Se for a empresa UNIME, lê a tabela sb1600.
Se for a empresa FAMA, lê a tabela sb1500.
Estou utilizando Hibernate com anotações e para cada empresa preciso criar um VO e mapear para um tabela especifica, por isso tenho alguns VOs parecidos, como abaixo:
ProdutoUnicVO, ProdutoUnimeVO,ProdutoFamaVO, etc…
Quero implementar um DAO para consulta genérico, não quero ter que criar várias classes ou métodos indenticos mudando apenas os VOs.
Por isso a necessidade de realizar CAST dinamicamente, pois após consultar um produto qualquer preciso modificar alguns dados dele, não apenas FlagEstoque, como no exemplo que citei acima.
victorwss , nesse caso que vc postou são identicos, como nos VOs abaixo:
@Entity
@Table(name="sb1010", schema="sigavalidacao")
@Where(clause="d_e_l_e_t_ <> '*'")
public class ProdutoUnicVO
{
@Id
@Column(name="b1_cod", insertable=false, updatable=false)
private String codgProduto;
... outros atributos
@Column (name="b1_estoque")
private String flagEstoque;
... outros atributos
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "b1_cod")
private ProdutoSaldoUnicVO produtoSaldoVO;
/** Referente a tabela saldo de produtos **/
public final ProdutoSaldoUnicVO getProdutoSaldoVO() { return produtoSaldoVO; }
public final void setProdutoSaldoVO(ProdutoSaldoUnicVO produtoSaldoVO) {
this.produtoSaldoVO = produtoSaldoVO;
}
... outros métodos get e set
}
@Entity
@Table(name="sb1500", schema="sigavalidacao")
@Where(clause="d_e_l_e_t_ <> '*'")
public class ProdutoFamaVO
{
@Id
@Column(name="b1_cod", insertable=false, updatable=false)
private String codgProduto;
... outros atributos
@Column (name="b1_estoque")
private String flagEstoque;
... outros atributos
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "b1_cod")
private ProdutoSaldoFamaVO produtoSaldoVO;
/** Referente a tabela saldo de produtos **/
public final ProdutoSaldoFamaVO getProdutoSaldoVO() { return produtoSaldoVO; }
public final void setProdutoSaldoVO(ProdutoSaldoFamaVO produtoSaldoVO) {
this.produtoSaldoVO = produtoSaldoVO;
}
... outros métodos get e set
}
Repare que neles existem diferenças de atributos, veja que são outros VOs mapeados para outras tabelas de BDs.
Nesse caso que esta pegando, eu até consigo resolver, mas vou ter que ficar repetindo vários métodos mudando pequenos detalhes, e ficar fazendo algumas verificações.
Tipo se o usuário logado for da empresa UNIC, utiliza esta método, se for FAMA utiliza este outro e cada método teria diferença apenas de váriaves declarada dentro dos métodos.
Porque não fazer assim :
[code]
interface ProdutoEmEstoque {
public boolean setFlagEstoque();
}
ProdutoUnicVO extends … implements ProdutoEmEstoque
ProdutoXXXVO extends … implements ProdutoEmEstoque
public T consultarProdutoPorCodg(Class objClass, String codgProduto){
Criteria criteria = this.getSession().createCriteria(objClass);
criteria.add(Restrictions.eq("codgProduto", StringUtil.preencheDir(codgProduto, 15, ' ')));
ProdutoEmEstoque produtoVO = (ProdutoEmEstoque) criteria.uniqueResult();
if(produtoVO.setFlagEstoque("S")) {
produtoVO.setFlagEstoque("Sim");
} else {
produtoVO.setFlagEstoque("Não");
}
return produtoVO;
}[/code]
Use uma interface para criar uma hirarquia paralela. Assim vc pdoe passar qq coisa que implemente ProdutoEmEstoque e vc sabe que haverá um metodo setFlagEstoque()
Note que a forma que vc está manipulando a exeção não é um tratamento correto.
Se vc não pode tratar a exceção não a capture.
Vou tentar seguir a sua solução e implementar utilizando Generics.
Se funcionar post a solução aqui.
Valew pessoal pela ajuda.