Vraptor 3 + Bug no Hibernate + Popular HashSet

24 respostas
rafaelob

Olá, estou com um problema no desenvolvimento da minha aplicação, que gostaria de compartilhar com vocês e ver se alguém tem uma ideia do que eu possa fazer

Bem, o Hibernate utiliza o Set para coleções, para solucionar o problema de itens duplicados, quando se faz um fetch com mais de uma coleção, se usar List e tentar usar fetch ele lançará uma exceção, foi o que aconteceu comigo.

Não usei o Set, pois o Vraptor não consegue popular um HashSet, o problema agora é que tenho consultas que fazem vários fetchs com as collections de meu bean, com isso tenho a exceção(cannot simultaneously fetch multiple bags).

Pesquisando, achei uma solução para os @ManyToMany que é o @CollectionId e adicionar uma coluna nesse relacionamento mxn, que seria única, com isso o hibernate não se perderia. Pois bem, criei uma no banco MYSQL auto increment. Pois bem, o problema é que tem um bug no hibernate, quando coloco a strategy = “identity”, ou seja o meu banco vai gerar o incremento.

@GenericGenerator(name = "generator", strategy = "identity") @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "core_blocks_modules", catalog = "core", joinColumns = { @JoinColumn(name = "cobm_cobs_id", nullable = false, updatable = false)}, inverseJoinColumns = { @JoinColumn(name = "cobm_como_id", nullable = false, updatable = false)}) @CollectionId( columns = @Column(name = "cobm_id"), type = @Type(type = "integer"), generator = "generator") public List<CoreModules> getCoreModules() { return this.coreModules; }

tenho esse erro, ao tentar inserir:

Informações: 13:52:52,709 TRACE BasicBinder:83 - binding parameter [2] as [INTEGER] - POST_INSERT_INDICATOR

Informações: 13:52:52,735  INFO AbstractBatchImpl:205 - HHH000010: On release of batch it still contained JDBC statements

Advertência: StandardWrapperValve[default]: PWC1406: Servlet.service() for servlet default threw exception
java.lang.ClassCastException: org.hibernate.id.IdentifierGeneratorHelper$2 cannot be cast to java.lang.Integer
	at org.hibernate.type.descriptor.java.IntegerTypeDescriptor.unwrap(IntegerTypeDescriptor.java:36)
	at org.hibernate.type.descriptor.sql.IntegerTypeDescriptor$1.doBind(IntegerTypeDescriptor.java:57)
	at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:92)
	at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:305)
	at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:300)
	at org.hibernate.persister.collection.AbstractCollectionPersister.writeIdentifier(AbstractCollectionPersister.java:863)
	at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1196)
	at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:58)
	at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)

Não sei mais o que fazer, tava com a versão 3.2.5 do Hibernate, mudei para 4.1.1 com o Plugin do Vraptor - Hibernate 4 e isso ainda não foi solucionado … Alguém tem uma idéia?

24 Respostas

rafaelob

Se eu mudo a strategy para “increment” ele funciona, porém não é isso que eu quero, já que dessa forma o hibernate busca a maior chave no banco, podendo ter problema com concorrência …

Bom, todo o problema ocasionado foi por conta que não posso usar Set para minhas collections, se não não consigo popular os objetos pela view usando o vraptor. =/

Estou pensando em usar a strategy = “uuid”, o que sugerem??

d34d_d3v1l

rafaelob:
Se eu mudo a strategy para “increment” ele funciona, porém não é isso que eu quero, já que dessa forma o hibernate busca a maior chave no banco, podendo ter problema com concorrência …

Bom, todo o problema ocasionado foi por conta que não posso usar Set para minhas collections, se não não consigo popular os objetos pela view usando o vraptor. =/

Estou pensando em usar a strategy = “uuid”, o que sugerem??

pq vc nao recebe a lista pelo parametro separado, no método no controller
para popular vc transfoorma a lista em set e pronto.
fim

rafaelob

Não tinha pensado tão simples assim, realmente talvez sua sugestão seja boa, tenho agora que mensurar o quanto isso vai impactar na minha app, a refatoração seria bem grande, pois gero as colunas automaticamente na view, já da forma certa para o Vraptor popular.

Valeu pela sugestão!! Quem tiver outra sugestão, por favor envia, até o momento eu criei essa coluna nova e estou usando com o UUID. Amanhã vou me reunir com a equipe e decidir que rumo tomar!

Quem quiser ajudar com outra sugestão, será bem vindo!

d34d_d3v1l

boa sorte cara.
abraços

Lucas_Cavalcanti

o vraptor não consegue popular Sets, pelo simples fato que eles não são indexados ([0], [1], [2]…)

uma solução de contorno seria criar um getter/setter que recebe/retorna uma List e converte pro Set correspondente.

e nos parametros do request apontar pro nome do setter

d34d_d3v1l

Lucas Cavalcanti:
o vraptor não consegue popular Sets, pelo simples fato que eles não são indexados ([0], [1], [2]…)

uma solução de contorno seria criar um getter/setter que recebe/retorna uma List e converte pro Set correspondente.

e nos parametros do request apontar pro nome do setter

É…Criar isso em um Util … para nao misturar na lógica =]

rafaelob

Lucas, mas se eu criar um get, pegando meu Set e transformando para List, ele não garante a ordem, certo? O Vraptor não precisa da ordem? já que ele popula indexando?

rafaelob

Pelo que eu vi, o Vraptor usa o get da propriedade para pegar o Tipo, correto? ele não pega o tipo pela declaração da propriedade em si, e sim pelo seu método get, depois ele popula uma list, e injeta no set, sem usar o get para nada. Correto? Tava tentando só sobrecarregar o método Set, mas vi que ele tava reclamando porque meu get retornava um Set, mesmo sendo a variável declarada como um List

Lucas_Cavalcanti

o vraptor vai usar o get e o set… os índices são pra setar várias propriedades do mesmo objeto, não necessariamente pra garantir ordem…

rafaelob

Lucas, nos testes que fiz mais cedo, coloquei na view assim. (Nomes aleatórios dos Objetos) MyObject.childList[].id e passei uns 3 ids. Coloquei breakpoints no get e no set de childList, eu não tenho uma variável childList, só uma variável child que é um HashSet.

No meu get, eu pego o objeto child(hashset) e transformo em lista e retorno, isso claro, não garante ordem nenhuma. No meu set eu recebo uma lista, e transformo em um HashSet. Pois bem, após submeter para minha app.

Por exemplo.
MyObject.childList[].id = 1
MyObject.childList[].id = 2
MyObject.childList[].id = 3

Somente o método Set é acionado, recebendo já uma list com esses 3 childs com os ids populados. O Get em nenhum momento foi adicionado, e é isso que eu desejo para que dê certo.

Se eu usasse os índices assim:

MyObject.childList[0].id = 1
MyObject.childList[1].id = 2
MyObject.childList[2].id = 3

MyObject.childList[0].name = "lala"
MyObject.childList[1].name = "lolo"
MyObject.childList[2].name = “kaka”

O Vraptor iria usar o get para retornar a lista para preencher a propriedade “name” de Child? Porque se sim, como o meu get vai retornar uma lista sem ordem, o vraptor poderia colocar os “names” em objetos trocados(Colocar o name do objeto com id 1 no objeto com id.2 e assim vai). Bem, fica minha dúvida!

Obrigado pela ajuda!

Lucas_Cavalcanti

vc chegou a testar isso?

se eu não me engano o vraptor monta a lista completa antes de chamar o set, não chega a chamar o getter.

rafaelob

Testei da primeira forma, sem os índices e o vraptor já manda a lista preenchida, ainda não testei passando os índices, vou testar para ver, mas acho que ele irá passar a lista já preenchida, não? E usa o get só para saber o tipo né?

Lucas_Cavalcanti

algo assim :wink:

rafaelob

Se o vraptor preenche a lista antes, porque não fazer um cast depois para um hashset? Acabaria com essa limitação de não poder usar um set

Lucas_Cavalcanti

não rola o cast… mas dá pra tentar usar o cara que cria a lista e depois converter em um hashset…

quer tentar fazer isso e contribuir pro vraptor?

rafaelob

Quero sim, Lucas! Eu tenho o source, vou trazer o projeto do meu trabalho para casa e vou investigar no Vraptor aonde é populado essa Lista e tentar modificá-lo. O cast que eu falo(Modo de falar), no caso é instanciar um HashSet passando uma List como parâmetro, eheh!

O Vraptor tem todo um padrão de codificação, né? Vou tentar contribuir, caso tenha algo a melhorar no código, aí sinalizam e eu mando de novo!

Valeu, Lucas!

Lucas_Cavalcanti

tem um padrão sim, mas eu vou te ajudando no caminho =)

pra implementar no IOGI, vc precisa criar uma classe parecida com essa:

o método instantiate pode só delegar pra essa classe mesmo e converter a lista do resultado pra um set.

daí depois que fizer isso, precisa adicionar esse cara aqui:

agora pra fazer no OGNL seja um pouco mais difícil…

em todo caso, tente escrever um teste automatizado pra isso =)

Valeu!

rafaelob

Humm, eu já olhei o código do Vraptor por curiosidade, tenho interesse em poder ajudar também. Vou dar uma estudada no que você me falou, agora uma dúvida de noob,rsrs, o que seria o IOGI e OGNL?

Abs

Lucas_Cavalcanti

são as duas implementações de ParametersProvider, que é o componente que pega os parâmetros da requisição e transforma em objetos.

Qualquer coisa dá um toque!

boneazul

Lucas Cavalcanti:
são as duas implementações de ParametersProvider, que é o componente que pega os parâmetros da requisição e transforma em objetos.

Qualquer coisa dá um toque!

Como anda essa issue Lucas ? Voces vão implementar isso ? Ou ja foi implementado ? Estou com o mesmo problema de ter que trabalhar com Set por conta do hibernate , seria interessante voces darem suporte a isso .

Lucas_Cavalcanti

Olá,

o garcia-jj está investigando como resolver isso…

quer participar dessa implementação?

boneazul

Lucas Cavalcanti:
Olá,

o garcia-jj está investigando como resolver isso…

quer participar dessa implementação?

Quero sim , a issue ja existe ? Pelo que vi tem um branch do guilhermesilveira sobre isso .

Lucas_Cavalcanti

posta algo lá =)

G

Faz uma semana que Lucas e eu estavamos discutindo sobre o assunto. Inicialmente fizemos o suporte somente ao IOGI, sendo que na verdade o SetInstantiator é um delegate para o ListInstantiator. Aqui tem um commit deste suporte inicial: https://github.com/caelum/vraptor/commit/6b848ef2c0277d24a9b3a9dfc41e3a027270b15a

O branch usado será o https://github.com/caelum/vraptor/tree/sets. Fique a vontade de discutir conosco, enviar pull requests, dar uns pitacos, etc etc etc :slight_smile:

Abraço

Criado 30 de agosto de 2012
Ultima resposta 20 de set. de 2012
Respostas 24
Participantes 5