[Resolvido] VRaptor - Deserializar objeto de select nulo

Prezados,

Há algum tempo eu venho tendo este problema, mas tenho tratado isto manualmente e pontualmente.
Quando uso um select no formuário que aponta para um id de um model relacionado, sendo este objeto opcional, ao submit se o select for nulo (não selecionado), no VRaptor chega um objeto que não é nulo, mas com as propriedades nulas.
Ocorre que ao salvar o hibernate reclama de objeto não transiente nulo, quando uso cascade pra merge.
Eu resolvo este problema verificando:

//significa que o objeto é nulo e não deveria ser serializado
if(objeto.getSubObjeto() != null && objeto.getSubObjeto().getId() == null) {
     objeto.setSubObjeto(null);
}

Isto resolve o problema, mas é chato ter que ficar fazendo na mão.
O problema acontece em outros casos também, sendo sempre o objeto não nulo com todas as propriedades nulas.
A pergunta é: tem como fazer com que o VRaptor identifique que este objeto deveria ser nulo e não deserializasse o mesmo?

Você deve receber o ID desse select e depois, caso precise, você vai buscar no banco de dados, certo?

Tudo manualmente. Faça um converter para esse tipo, algo assim:

[code]@Convert(User.class)
public class UserConverter implements Converter<User> {

private final Logger logger = LoggerFactory.getLogger(this.getClass());
private UserDAO dao;

public UserConverter(UserDAO dao) {
	this.dao = dao;
}

@Override
public User convert(String value, Class&lt;? extends User&gt; type,
		ResourceBundle bundle) {
	try {
		return this.dao.get(Long.parseLong(value));
	} catch (NumberFormatException e) {
		logger.warn(&quot;Unable to convert to long. Value: '&quot; + value + &quot;'\n&quot;
				+ e.getMessage());
	} catch (HibernateException e) {
		logger.warn(&quot;Unable to get this record. Value: '&quot; + value + &quot;'\n&quot;
				+ e.getMessage());
	} catch (Exception e) {
		logger.warn(&quot;An error occured. Value: '&quot; + value + &quot;'\n&quot;
				+ e.getMessage());
	}
	return null;
}

}[/code]

Entendi.

Será que consigo ir mais além e fazer de forma mais genérica, pra não ter que fazer um pra cada?

registra esse filtro:

ele só se aplica aos parametros que terminam com .id, se vc quiser remover todos os parametros vazios mesmo, mude o método apply que tem lá no meio

show de bola Lucas.

vlw

Lucas eu estava debugando e o post não passa pelo filter e a deserialização está ocorrendo da mesma forma

O filter está sendo aplicado pois passa por ele em outras ocasiões, mas para a situação de post não está.

Coloquei o url-pattern /* no web.xml é isto mesmo?

Não sei se fui bem entendido, mas o que eu quero é se um objeto relacionado for nulo, ou seja, não foi selecionado na view o seu id, chegue no vraptor nulo e não instanciado com a propriedade id nula.
Esta solução resolveria?

Editei para postar mais um detalhe
No debug do vraptor está ocorrendo
11:04:52,559 DEBUG [OgnlParametersProvider] Applying bairro.id with []

Um exemplo do problema, como bairro é opcional, quero que o bairro chegue nulo se não for selecionado.
Acho que se o filter pegasse isto realmente iria funcionar, mas não está filtrando por alguma coisa que fiz errado (copiei exatamente o seu filter e o registrei no web.xml)

esse filtro tem que ser registrado antes do filtro do VRaptor, daí vai funcionar.

eu fiz assim e não funfou (tem o filter do sitemesh no meio):

      <filter>
		<filter-name>ParametersFilter</filter-name>
		<filter-class>br.com.flexait.esab.interceptor.ParametersFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>ParametersFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter>
		<filter-name>sitemesh</filter-name>
		<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>sitemesh</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter>
		<filter-name>vraptor</filter-name>
		<filter-class>br.com.caelum.vraptor.VRaptor</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>vraptor</filter-name>
		<url-pattern>/*</url-pattern>
		<dispatcher>FORWARD</dispatcher>
		<dispatcher>REQUEST</dispatcher>
	</filter-mapping>

estranho não funcionar…

vc tentou colocar os dispatchers?

<dispatcher>FORWARD</dispatcher>  
<dispatcher>REQUEST</dispatcher>  

pois eh, não funciona mas descobri o problema.
estou usando ognl pra fazer upload, devido a um problema anterior onde upload de input file vazio dava exception?
removi o input file e tirei o enctype do form e funcionou, o parametro não chegou no vraptor.

alguma sugestão de como resolver isto agora?

se isso é durante um upload a solução não funciona mesmo…

no upload os parametros vêm diferentes =(

nesse caso vc teria que sobrescrever outro componente do VRaptor, talvez o componente que gera os parâmetros…

teria que copiar essa classe inteira pro seu projeto, anotá-la com @Component, e sobrescrever o método parametersThatStartWith pra não retornar parametros vazios (mesma solução do filtro quase)

O caldo engrossou…

Rapaz, eu consegui resolver o problema (somente criando uma regra após o filterKeys gerando outro map), mas tive que rescrever mais duas classes, que possuiam métodos não visíveis (OgnlFacade e VRaptorConvertersAdapter).

O ideal era melhorar a classe OgnlParametersProvider para permitir ser mais extensível, igual é diversas outras funcionalidade do VRaptor.

abre uma issue lá no VRaptor pra fazer isso:

ou transforme esses métodos em protected e abra um pull request =)

dá pra editar pelo próprio github =)

Apenas mudado os métodos pra protected e extendendo a classe vai funciona, ou gera duplicidade de dependência na injeção?
assim só sobrecarregaria o método em questão!

nota: a propriedade request tb deve ser protected neste caso, e pra ficar mais flexível mudaria o acesso de todas!

acho que mudar o modificador dos atributos não é legal… se a classe filha precisar de request ela já vai ter recebido no construtor e pode colocar no seu próprio atributo.

e não geraria essa duplicidade que vc falou não.

Ok Lucas

Abri a issue e fiz o pull request.

Vlw a ajuda

Valeu! Só teve um detalhezinho, um public que não deveria virar protected. Corrige lá plz

Desatenção de sempre!
sorry

Usei pouco o github pra colaboração, por isso me enrolei.

Vlw a força.