[Resolvido] VRaptor - Deserializar objeto de select nulo

18 respostas
denilsont

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?

18 Respostas

Rafael_Guerreiro

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:
@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<? extends User> type,
			ResourceBundle bundle) {
		try {
			return this.dao.get(Long.parseLong(value));
		} catch (NumberFormatException e) {
			logger.warn("Unable to convert to long. Value: '" + value + "'\n"
					+ e.getMessage());
		} catch (HibernateException e) {
			logger.warn("Unable to get this record. Value: '" + value + "'\n"
					+ e.getMessage());
		} catch (Exception e) {
			logger.warn("An error occured. Value: '" + value + "'\n"
					+ e.getMessage());
		}
		return null;
	}
}
denilsont

Entendi.

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

Lucas_Cavalcanti

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

denilsont

show de bola Lucas.

vlw

denilsont

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)

Lucas_Cavalcanti

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

denilsont

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

estranho não funcionar…

vc tentou colocar os dispatchers?

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

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?

Lucas_Cavalcanti

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

<aside class="onebox githubblob">
  <header class="source">
      <a href="https://github.com/caelum/vraptor/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/http/ognl/OgnlParametersProvider.java#L204" target="_blank">github.com</a>
  </header>
  <article class="onebox-body">
    <h4><a href="https://github.com/caelum/vraptor/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/http/ognl/OgnlParametersProvider.java#L204" target="_blank">caelum/vraptor/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/http/ognl/OgnlParametersProvider.java#L204</a></h4>
<pre class="onebox"><code class="lang-java"><ol class="start lines" start="194" style="counter-reset: li-counter 193 ;">
<li>		for (int i = 0; i < values.length; i++) {</li>
<li>			Array.set(array, i, convert(arrayType, values[i], bundle));</li>
<li>		}</li>
<li>		return array;</li>
<li>	}</li>
<li>
</li>
<li>	protected Class getActualType(Type type) {</li>
<li>		return (Class) ((ParameterizedType) type).getActualTypeArguments()[0];</li>
<li>	}</li>
<li>
</li>
<li class="selected">	protected Map<String, String[]> parametersThatStartWith(String name) {</li>
<li>		Map<String, String[]> requestNames = filterKeys(request.getParameterMap(), containsPattern('^' + name));</li>
<li>		return new TreeMap<String, String[]>(requestNames);</li>
<li>	}</li>
<li>}</li>
</ol>

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)

denilsont

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.

Lucas_Cavalcanti

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 =)

denilsont

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!

Lucas_Cavalcanti

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.

denilsont

Ok Lucas

Abri a issue e fiz o pull request.

Vlw a ajuda

Lucas_Cavalcanti

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

denilsont

Desatenção de sempre!
sorry

denilsont

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

Vlw a força.

Criado 25 de janeiro de 2013
Ultima resposta 30 de jan. de 2013
Respostas 18
Participantes 3
Casa do Codigo Casa do Codigo — Livros de tecnologia Livros de programacao, infraestrutura e inovacao
Lumina Lumina: a IA que te traz resultados Prompts prontos por especialistas. Resolva seus problemas de verdade.