Inicialização reflexiva de atributos final  XML
Índice dos Fóruns » Java Avançado
Autor Mensagem
barenko
JavaBaby
[Avatar]

Membro desde: 07/04/2008 21:09:30
Mensagens: 81
Offline

Olá pessoal! Estou com um conflito entre a inicialização do objeto e a inicialização reflexiva de atributos final.

É o seguinte:

Estou fazendo uma espécie de DAO voltado para programadores oracle, ou seja: ele terá uma sintaxe bem similar à DML. Para conseguir a flexibilidade necessária para gerar selects complexos, precisei criar um Pojo inteligente (DbTable) que se encarrega de carregar toda a infraestrutura de mapeamento com as tabelas do banco. Os "Beans" serão filhos da DbTable e terão que declarar suas colunas como objetos TableColumn anotados.

Para assegurar que os selects desse DAO sejam feitos de forma muito similar à da DML, fiz que esses atributos fossem publicos e finais. Nota: esses atributos representam colunas e naõ dados.

Devido aos atributos de coluna serem publicos, eu os tornei final p/ evitar problemas. Porém ao fazer isso, o java me obriga a inicializar a variável (sendo assim, atribuo null nela).

O problema aparece quando vou inicializar meu "Bean". Pela pilha de inicialização, o java chama o super do construtor (DbTable) que é encarregado de instanciar os atributos TableColumn da classe filha via reflexão. Porém ao executar o construtor da classe (Client), essa anula o TableColumn instanciado pela DbTable!


Seguem abaixo os códigos que exemplificam meu problema (Eu simplifiquei ao máximo as classes apenas para evidenciar o problema em si).






Saída:

Inicio de DbTable()...
DbTable() Instanciou o atributo id com [TableColumn@1c184f4]
Clients() Instanciou o atributo id com [null]
ID após o termino da inicialização: null


Não consegui descobrir como modificar um atributo para final via reflexão, se alguém souber como fazer, seria muito útil.

Transformar os objetos TableColumn em static também naõ ajudará, pois isso causará problemas para referenciar as colunas do select com as tabelas envolvidas.


Alguém poderia me ajudar? Até com idéias mirabolantes de magia negra?

This message was edited 1 time. Last update was at 08/10/2009 15:19:48

[Email]
palmadias
JavaTeenager

Membro desde: 08/07/2008 07:41:08
Mensagens: 192
Localização: São Paulo/SP
Offline

Vc já pensou em usar JPA?

Parece que vc tá reinventando a roda.

http://palmadias.blogspot.com/
[WWW] [MSN]
barenko
JavaBaby
[Avatar]

Membro desde: 07/04/2008 21:09:30
Mensagens: 81
Offline

Olá!

Já pensei em JPA sim, só q encontrei alguns problemas nessa abordagem... talvez por inexperiência minha no assunto...

Por exemplo:
Tenho meu genericDao com beans anotados. Se quero os nomes dos clientes de RG X, Y e Z, faço 3 pesquisas (queryBySample) criando um Bean e setando o RG para cada um dos valores e recebo 3 beans que possuem todos os atributos do bean populados.

Em outras palavras:
O q deveria ser isso:
select name from clients where rg in(X,Y,Z)

Se transforma nisso:
select id, name, address, age, is_active, ......, created_at from clients where rg = X
select id, name, address, age, is_active, ......, created_at from clients where rg = Y
select id, name, address, age, is_active, ......, created_at from clients where rg = Z

3 requisições de todos os campos ao banco de dado. Em tabelas pequenas, tudo bem. Mas e para sistemas que possuem tabelas de 150 campos? E se o desempenho for critico? Entende a origem do meu problema?

Minha idéia é criar algo assim:
Client client = new Client();
select(client.name).from(client).where(client.rg.in(X,Y,Z))

E com isso, o meu framework montaria um único select e retornaria os objetos que eu preciso manipular.

Claro, se já existir algo capaz de fazer isso disponível, eu tratarei de ver na mesma hora!

This message was edited 2 times. Last update was at 08/10/2009 16:22:52

[Email]
barenko
JavaBaby
[Avatar]

Membro desde: 07/04/2008 21:09:30
Mensagens: 81
Offline

E ai, ninguém tem nenhuma idéia p/ tentar driblar o problema?
[Email]
Marky.Vasconcelos
Moderador
[Avatar]

Membro desde: 11/04/2007 18:18:20
Mensagens: 5932
Localização: São Paulo/SP
Offline

Eu acho que hibernate ainda te resolve isso.


Facebook @MarkyHitchhiker +Mark WP: MarkyTech's

Projects:
Android Roadmap - Aprenda Android do inicio (Java é o unico pre-requisito)
Towel ( ObjectTableModel & Swing & Utils )
Tower Defense Game - Java2D [Open-Source] [How-to-play]
EVGD: Programação de jogos (links) Ponto V! - Desenvolvimento de jogos para indies, curiosos e profissionais

DefaultTableModel?! PARE! Não faça isso! Faça melhor!

Dicas: Faça perguntas inteligentes! ; MigLayout ; GridBagLayout (Joke)

Develop games is fantastic, with words you can make worlds!!!

DON'T PANIC!
MarkyHitchhiker's Blog!
[WWW] [MSN]
Lavieri
GUJ Master
[Avatar]

Membro desde: 27/01/2004 13:39:31
Mensagens: 1851
Localização: João Pessoa / PB
Offline

resolve mesmo

na verdade da pra fazer melhor com hibernate



com JPA tambem da pra fazer

JPA QL = "c From Client as c where c.rg in(X,Y,Z)";

se vc só quer o nome = "c.name From Client as c where c.rg in(X,Y,Z)";

não tente reiventar a roda, que da muitaaaaaaaa dor de cabeça ^^ .... pessoal do hibernate ta nessa a nos já

This message was edited 1 time. Last update was at 14/10/2009 09:53:04


Sun Certified Java Programmer (SCJP 6)

"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."
-Martin Fowler et al, Refactoring: Improving the Design of Existing Code, 1999

Meu blog -> http://blog.tomazlavieri.com.br/
[ICQ]
barenko
JavaBaby
[Avatar]

Membro desde: 07/04/2008 21:09:30
Mensagens: 81
Offline

Interessante, essas dicas resolvem mesmo o problema da clausula "IN". Muito bom!


Só faltam alguns outros problemas, vou listar aqui para vcs verem:

  • Trazer apenas algumas colunas da tabela ao invez da linha toda - Tem lugares q eu só preciso de 2 ou 3 campos e não de 150... e cá entre nós, fazer um beam p/ representar cada "visão" da mesma tabela (assim traria apenas as colunas q estao no bean) é algo um tanto qto estúpido e sujo p/ se fazer num código... eu vejo isso como retrabalho desnecessário, aumento potencial de pontos de bug e dificuldade no entendimento posterior


  • Caso eu queira fazer um count ou chamar alguma outra função de banco na lista de colunas do select - O q eu vi até agora é q isso deve ser feito por fora, no melhor estilo RAW JDBC


  • Fazer agrupamentos "group by" ou "having by" com componentes nativos - novamente sem recorer ao velho RAW JDBC


  • Criar joins com tabelas diferentes e obter algo como uma lista dos objetos utilizados no select - Por ex: se eu fizer um join para obter 2 colunas de cliente e 2 colunas de produto, eu receberia 2 objetos por linha retornada contendo os dados das minhas colunas


  • Além disso eu tenho fortes limitações cerebrais e motoras que me bloqueiam sempre que eu vejo que o select que eu quero executar possui apenas 15 singelas linhas bem identadas e de fácil entendimento se transformam em um monstro amorfo de cerca de 30 linhas. - Claro q exagerei, na maioria dos casos normais de tabela<->bean isso não ocorre. Esses problemas costumam aparecer em relatórios e aplicações de análise, que precisam cruzar dados das mais diferentes formas



  • Eu não quero provocar guerra ou discussões fervorozas em defesa do hibernate, JPA ou sei lá o q. Apenas estou espondo os problemas que já presenciei qdo decidi me aventurar pelos mares do hibernate e da JPA.

    Por isso decidi fazer um framework de persistência voltado à programação de scripts (mesma utilizada pelos bancos de dados relacionais padrões de mercado) ao invés de fazê-lo voltado à programação orientada a objetos.


    Aliás, q mal há em criar uma roda com câmara e pneu quando tudo que se tem são rodas de madeira e metal?
    [Email]
    Marky.Vasconcelos
    Moderador
    [Avatar]

    Membro desde: 11/04/2007 18:18:20
    Mensagens: 5932
    Localização: São Paulo/SP
    Offline

    barenko wrote:Interessante, essas dicas resolvem mesmo o problema da clausula "IN". Muito bom!


    Só faltam alguns outros problemas, vou listar aqui para vcs verem:

  • Trazer apenas algumas colunas da tabela ao invez da linha toda - Tem lugares q eu só preciso de 2 ou 3 campos e não de 150... e cá entre nós, fazer um beam p/ representar cada "visão" da mesma tabela (assim traria apenas as colunas q estao no bean) é algo um tanto qto estúpido e sujo p/ se fazer num código... eu vejo isso como retrabalho desnecessário, aumento potencial de pontos de bug e dificuldade no entendimento posterior



  • O Hibernate tem o esquema de apenas carregar o dado do atributo quando voce fizer um getAlgo no objeto. Então acho que mesmo usando duas colunas voce pode carregar o objeto inteiro sem se preocupar.

    PS: Claro se voce não mudar essa função para o modo EAGER ou então não pegar da Session com o comando get(Seriable id)

    barenko wrote:
  • Caso eu queira fazer um count ou chamar alguma outra função de banco na lista de colunas do select - O q eu vi até agora é q isso deve ser feito por fora, no melhor estilo RAW JDBC





  • Quanto a do group by e havin by e a outra questão não sei te responder.

    Facebook @MarkyHitchhiker +Mark WP: MarkyTech's

    Projects:
    Android Roadmap - Aprenda Android do inicio (Java é o unico pre-requisito)
    Towel ( ObjectTableModel & Swing & Utils )
    Tower Defense Game - Java2D [Open-Source] [How-to-play]
    EVGD: Programação de jogos (links) Ponto V! - Desenvolvimento de jogos para indies, curiosos e profissionais

    DefaultTableModel?! PARE! Não faça isso! Faça melhor!

    Dicas: Faça perguntas inteligentes! ; MigLayout ; GridBagLayout (Joke)

    Develop games is fantastic, with words you can make worlds!!!

    DON'T PANIC!
    MarkyHitchhiker's Blog!
    [WWW] [MSN]
    barenko
    JavaBaby
    [Avatar]

    Membro desde: 07/04/2008 21:09:30
    Mensagens: 81
    Offline

    Mark_Ameba wrote:

    O Hibernate tem o esquema de apenas carregar o dado do atributo quando voce fizer um getAlgo no objeto. Então acho que mesmo usando duas colunas voce pode carregar o objeto inteiro sem se preocupar.

    PS: Claro se voce não mudar essa função para o modo EAGER ou então não pegar da Session com o comando get(Seriable id)


    Fiquei curioso qto a como funciona isso...

    Por ex:

    Eu tenho um bean (B) com 3 atributos (a1, a2, a3).
    Configuro o Hibernate para Fetch.SELECT (ou o LAZY depreciado).
    Até ai, ok... a partir de agora, corrija-me se eu estiver errado:

    Eu quero obter apenas o a1. Ao efetuar um select com o hibernate, eu passo o bean e ele faz um equivalente à:

    Pode ser que o hibernate não carregue as colunas no bean (para otimizar desempenho), mas os valores estarão em seu cache interno. Se eu precisar do conteúdo do a1 fazendo algo como :

    O hibernate usará o mock que ele me retornou para obter o valor do campo a1 que estava no cache. Não é isso?

    Se for isso, utilizar ou não Lazy implicará no mesmo problema: trazer tudo da linha do banco no select...


    [Email]
    Marky.Vasconcelos
    Moderador
    [Avatar]

    Membro desde: 11/04/2007 18:18:20
    Mensagens: 5932
    Localização: São Paulo/SP
    Offline

    Se voce fazer o getClass do objeto do Hibernate (Que provavelmente é encapsulado como um seu) voce vai ser que este extends o seu.
    O hibernate cria novas classes em execução e nos getters ele coloca código para quando for acessado o atributo ele faça o select no banco.

    Facebook @MarkyHitchhiker +Mark WP: MarkyTech's

    Projects:
    Android Roadmap - Aprenda Android do inicio (Java é o unico pre-requisito)
    Towel ( ObjectTableModel & Swing & Utils )
    Tower Defense Game - Java2D [Open-Source] [How-to-play]
    EVGD: Programação de jogos (links) Ponto V! - Desenvolvimento de jogos para indies, curiosos e profissionais

    DefaultTableModel?! PARE! Não faça isso! Faça melhor!

    Dicas: Faça perguntas inteligentes! ; MigLayout ; GridBagLayout (Joke)

    Develop games is fantastic, with words you can make worlds!!!

    DON'T PANIC!
    MarkyHitchhiker's Blog!
    [WWW] [MSN]
    barenko
    JavaBaby
    [Avatar]

    Membro desde: 07/04/2008 21:09:30
    Mensagens: 81
    Offline

    Mark_Ameba wrote:O hibernate cria novas classes em execução e nos getters ele coloca código para quando for acessado o atributo ele faça o select no banco.


    Vou ver se eu entendi:

    Bean: B
    Atributos b1, b2, b3,... bn
    Mark_Ameba 'levemente modificado wrote:

    Isso deve recuperar o objeto com b3 = X.
    Por trás o hibernate faz o q? um select p/ recuperar apenas os ids?

    Blz, se for isso, vai ficar bem rápido para obter as referências reais dos objetos (id's)

    Ai, vc disse q o hibernate faria um select por atributo. Então se eu fizer isso:

    O hibernate, por trás, fará isso?

    Então, se eu fizer isso:

    O hibernate fará isso?

    Deduzi isso pensando na pilha de chamadas do java. Em lazy é isso mesmo q ocorre?
    [Email]
    Lavieri
    GUJ Master
    [Avatar]

    Membro desde: 27/01/2004 13:39:31
    Mensagens: 1851
    Localização: João Pessoa / PB
    Offline

    vc pode escolher que campos trazer no hibernate, mais isso vai te custar ter q popular o objeto java, o que é uma chatisse...

    objetos com 150 atributos são uma bizzarrice do ponto de vista OO, não importa se na tua tabela tem 150 atributos, em Java, vc pode modelar para ser varios objetos com varios atributos...

    é possivel ainda agrupos N atributos de uma mesma tabela em objetos @Embedabble, esses objetos funciona mais ou menos assim: e neste caso tornas esses embeddable groups lazy





    mesmo assim é possivel separar uma mesma tabela em N objetos java, com relacionamentos 1-1, para não puxar a linha toda de uma vez

    This message was edited 1 time. Last update was at 16/10/2009 09:05:51


    Sun Certified Java Programmer (SCJP 6)

    "Any fool can write code that a computer can understand. Good programmers write code that humans can understand."
    -Martin Fowler et al, Refactoring: Improving the Design of Existing Code, 1999

    Meu blog -> http://blog.tomazlavieri.com.br/
    [ICQ]
    Mauricio Linhares
    Moderador
    [Avatar]

    Membro desde: 09/01/2005 23:28:22
    Mensagens: 3717
    Localização: João Pessoa, Paraíba - Brasil
    Offline

    Não, não é isso que acontece, o Hibernate não deixa você selecionar os campos que ele vai trazer, ele sempre vai buscar todas as colunas, o que pode ser lazy loaded são as associações.

    Usando hibernate você faria assim - http://docs.jboss.org/hibernate/stable/core/reference/en/html/querysql.html#d0e13696

    Mas tabelas com 150 colunas são um lindo sinal de que o banco de dados está com sérios problemas


    Meu blog sobre desenvolvimento | My Last.fm | @mauriciojr

    Screencast de Introdução a linguagem Objective-C
    [WWW]
    Lavieri
    GUJ Master
    [Avatar]

    Membro desde: 27/01/2004 13:39:31
    Mensagens: 1851
    Localização: João Pessoa / PB
    Offline

    Mauricio Linhares wrote:Mas tabelas com 150 colunas são um lindo sinal de que o banco de dados está com sérios problemas

    quote++

    agree

    Sun Certified Java Programmer (SCJP 6)

    "Any fool can write code that a computer can understand. Good programmers write code that humans can understand."
    -Martin Fowler et al, Refactoring: Improving the Design of Existing Code, 1999

    Meu blog -> http://blog.tomazlavieri.com.br/
    [ICQ]
    Marky.Vasconcelos
    Moderador
    [Avatar]

    Membro desde: 11/04/2007 18:18:20
    Mensagens: 5932
    Localização: São Paulo/SP
    Offline

    É algo parecido com isso mesmo.

    Mas o comando get da Session já retorna com o select completo, para ter esse efeito voce precisa carregar com o load.


    Pra voce ver.

    No hibernate.properties coloque a opção para mostrar o SQL
    acho que é hibernate.show_sql=true da uma pesquisada.

    Depois faça um código como abaixo e rode pra ver como isso funciona.


    Facebook @MarkyHitchhiker +Mark WP: MarkyTech's

    Projects:
    Android Roadmap - Aprenda Android do inicio (Java é o unico pre-requisito)
    Towel ( ObjectTableModel & Swing & Utils )
    Tower Defense Game - Java2D [Open-Source] [How-to-play]
    EVGD: Programação de jogos (links) Ponto V! - Desenvolvimento de jogos para indies, curiosos e profissionais

    DefaultTableModel?! PARE! Não faça isso! Faça melhor!

    Dicas: Faça perguntas inteligentes! ; MigLayout ; GridBagLayout (Joke)

    Develop games is fantastic, with words you can make worlds!!!

    DON'T PANIC!
    MarkyHitchhiker's Blog!
    [WWW] [MSN]
     
    Índice dos Fóruns » Java Avançado
    Ir para:   
    Powered by JForum 2.1.8 © JForum Team