Vraptor 3 + Bug no Hibernate + Popular HashSet

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?

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??

[quote=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??[/quote]

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

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!

boa sorte cara.
abraços

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

[quote=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[/quote]

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

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?

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

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…

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!

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.

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é?

algo assim :wink:

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

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?

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!

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!

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

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!