Prioridade de uso dos Serializers, disponíveis, no VRaptor

7 respostas
acdesouza

Caros,

Estou tentando usar o vraptor-gson-plugin, para serializar os JSONs usando a API Gson, do Google.

O problema é que a escolha, por parte do VRaptor, de qual a implementação de br.com.caelum.vraptor.serialization.JSONSerialization não parece ser determinística. Ou seja, quando eu inicio a aplicação uma vez, ele usa o padrão do VRaptor, com XStream. Quando eu executo uma outra vez, usa o Gson.

Observe que, diferente do que a última frase posso insinuar, não é intercalado. É, como se o VRaptor estivesse jogando cara-ou-coroa entre as duas implementações e quem ganha é usado.

Para resolver o problema já tentei as seguintes abordagens:

  1. Criar um br.com.caelum.vraptor.util.gson.GsonSerializationProvider, que herda de SpringProvider e colocar ele no web.xml:

<context-param> <param-name>br.com.caelum.vraptor.packages</param-name> <param-value>br.com.caelum.vraptor.restfulie</param-value> </context-param> <context-param> <param-name>br.com.caelum.vraptor.provider</param-name> <param-value>br.com.caelum.vraptor.util.gson.GsonSerializationProvider</param-value> </context-param>

Neste caso, imaginei que ao ativar o restfulie, o pacote de serialização padrão ganhava prioridade.

  1. Colocar o pacote onde estão os serializadores no web.xml

<context-param> <param-name>br.com.caelum.vraptor.packages</param-name> <param-value>br.com.caelum.vraptor.serialization.gson,br.com.caelum.vraptor.restfulie</param-value> </context-param>

Aqui não imagino uma explicação.

Imaginei que deveria rolar uma forma de “desregistrar”, no VRaptor, o serializador padrão de JSON. Mas, não achei como.

Alguém teria uma idéia?

7 Respostas

acdesouza

O lance é o seguinte:

O VRaptor recupera os Serializers e os coloca em uma lista.
Para evitar o problema que eu relatei, ele ordena esta lista colocando os Serializers, que começam com o pacote br.com.caelum.vraptor.serialization no final.
Só que o pacote da minha classe é br.com.caelum.vraptor.serialization.gson, o que fazia com que ele colocasse como igual.

Então mudei o nome do pacote para br.com.contrib.vraptor.serialization, mas não resolveu.

Debugar o VRaptor me fez acreditar que o problema está na classe br.com.caelum.vraptor.serialization.DefaultRepresentationResult.

Ela recebe uma lista de Serialization e a ordena. O problema é exatamente esta ordenação. Dependendo da ordem inicial da lista, a lista ordenada é modificada.

Alguém poderia ajudar? Seguem os exemplos:

Caso em que dá erro ============
Ordem original                    Ordem errada
[0]	HTMLSerialization             [0]	RestfulSerialization         
[1]	XStreamXMLSerialization       [1]	RestfulSerializationJSON     
[2]	XStreamJSONSerialization      [2]	GsonRestfulSerializationJSON 
[3]	RestfulSerialization          [3]	GsonJSONSerialization        
[4]	RestfulSerializationJSON      [4]	HTMLSerialization            
[5]	GsonRestfulSerializationJSON  [5]	XStreamXMLSerialization      
[6]	GsonJSONSerialization         [6]	XStreamJSONSerialization
======================================= Casos em que não dá erro ===========================
Ordem original                    Ordem certa
[0]	HTMLSerialization             [0]	RestfulSerialization         
[1]	XStreamJSONSerialization      [1]	GsonRestfulSerializationJSON 
[2]	XStreamXMLSerialization       [2]	RestfulSerializationJSON     
[3]	RestfulSerialization          [3]	GsonJSONSerialization        
[4]	GsonRestfulSerializationJSON  [4]	HTMLSerialization            
[5]	RestfulSerializationJSON      [5]	XStreamJSONSerialization     
[6]	GsonJSONSerialization         [6]	XStreamXMLSerialization
*********************************************************
Ordem original                    Ordem certa
[0]	HTMLSerialization             [0]	GsonRestfulSerializationJSON 
[1]	XStreamJSONSerialization      [1]	RestfulSerialization         
[2]	XStreamXMLSerialization       [2]	GsonJSONSerialization        
[3]	GsonRestfulSerializationJSON  [3]	RestfulSerializationJSON     
[4]	RestfulSerialization          [4]	HTMLSerialization            
[5]	GsonJSONSerialization         [5]	XStreamJSONSerialization     
[6]	RestfulSerializationJSON      [6]	XStreamXMLSerialization
============================================
Lucas_Cavalcanti

o que vc pode fazer é sobrescrever o componente RepresentationResult, ordenando do jeito que vc precisa…

só copiar a classe https://github.com/caelum/vraptor/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/serialization/DefaultRepresentationResult.java para o seu projeto, e ordenar do jeito que vc precisa…

mas como vc tá fazendo um plugin, o que a implementação padrão está fazendo é dando menos prioridade para serializers do pacote br.com.caelum.vraptor.serialization.

o que vc pode fazer é trocar o pacote do plugin pra outra coisa (tipo br.com.acdesouza.serialization), isso já vai resolver o problema.

vc não precisa do provider. Ao invés disso, anote as classes do plugin com @Component, e registre no packages o pacote base do plugin.

acdesouza

Lucas Cavalcanti:
o que vc pode fazer é sobrescrever o componente RepresentationResult, ordenando do jeito que vc precisa…

só copiar a classe https://github.com/caelum/vraptor/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/serialization/DefaultRepresentationResult.java para o seu projeto, e ordenar do jeito que vc precisa…

Beleza. Isso resolve no projeto atual.

Isso. É, exatamente, isso que deveria estar acontecendo. Mas, debugando a classe br.com.caelum.vraptor.serialization.DefaultRepresentationResult, observei que a ordenação não está funcionando.
Como eu disse, a ordenação não está sendo determinística, isto é, dependendo da ordem de entrada o resultado muda. Estou pensando em remover o PackageComparator da classe para testá-lo.

Imaginei que deveria resolver. Mas, não deu certo. O histórico do nome dos pacotes foi:
[list]br.com.caelum.vraptor: descobri o problema;[/list]
[list]br.com.contrib.vraptor: tentativa de resolver;[/list]
[list]br.com.beyondclick.vraptor: segunda tentativa de resolver;[/list]
E, nos dois casos deu o problema.

Eu não estou usando. Foi um momento de desespero para ver se resolvia :oops:

Lucas_Cavalcanti

alguma sugestão de como fazer a ordenação dos serializers?

acdesouza
Lucas Cavalcanti:
alguma sugestão de como fazer a ordenação dos serializers?

Extrai o Comparator para um arquivo, e fiz um teste para ele:

package br.com.caelum.vraptor.serialization;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import junit.framework.Assert;

import org.junit.Test;

import pacote.antes.da.caelum.DumbSerialization;
import br.com.caelum.vraptor.restfulie.serialization.RestfulSerialization;
import br.com.caelum.vraptor.serialization.xstream.XStreamJSONSerialization;
import br.com.caelum.vraptor.serialization.xstream.XStreamXMLSerialization;

public class PackageComparatorTest {

	@Test
	public void shouldSortBasedOnPackageNamesLessPriorityToCaelumInitialList3rdPartyFirst() {
		List<Serialization> serializers = new ArrayList<Serialization>();

		serializers.add(new DumbSerialization());
		serializers.add(new XStreamXMLSerialization(null, null, null));
		serializers.add(new XStreamJSONSerialization(null, null, null));
		serializers.add(new HTMLSerialization(null, null));
		serializers.add(new RestfulSerialization(null, null, null, null, null));

		Collections.sort(serializers, new PackageComparator());
		
		Assert.assertEquals("", "pacote.antes.da.caelum", serializers.get(0).getClass().getPackage().getName());

	}

	@Test
	public void shouldSortBasedOnPackageNamesLessPriorityToCaelumInitialList3rdPartyLast() {
		List<Serialization> serializers = new ArrayList<Serialization>();
		
		serializers.add(new XStreamXMLSerialization(null, null, null));
		serializers.add(new XStreamJSONSerialization(null, null, null));
		serializers.add(new HTMLSerialization(null, null));
		serializers.add(new RestfulSerialization(null, null, null, null, null));
		serializers.add(new DumbSerialization());
		
		Collections.sort(serializers, new PackageComparator());
		
		Assert.assertEquals("", "pacote.antes.da.caelum", serializers.get(0).getClass().getPackage().getName());
		
	}
}
package pacote.antes.da.caelum;

import br.com.caelum.vraptor.serialization.Serialization;
import br.com.caelum.vraptor.serialization.Serializer;

/**
 * Test Serialization's comparator
 *  
 * @author acdesouza
 */
public class DumbSerialization implements Serialization {

	public <T> Serializer from(T object) {
		return null;
	}

	public <T> Serializer from(T object, String alias) {
		return null;
	}

	public boolean accepts(String format) {
		return false;
	}

}
package br.com.caelum.vraptor.serialization;

import java.util.Comparator;

final class PackageComparator implements Comparator<Serialization> {
	private int number(Serialization s) {
		if (s.getClass().getPackage().getName().startsWith("br.com.caelum.vraptor.serialization")) {
			return 1;
		}
		return 0;
	}

	public int compare(Serialization o1, Serialization o2) {
		return number(o1) - number(o2);
	}
}

O primeiro passa, o segundo quebra. Estou analisando para corrigir.

acdesouza

Parece que achei :!: :!:

O lance é que o Comparator dá baixa prioridade para o pacote: br.com.caelum.vraptor.serialization

E, o JSON está em br.com.caelum.vraptor.restfulie.serialization.

Por isso que, dependendo da ordem, funciona. Porque o Serialization do plugin tem que estar na frente do Serialization do Restfulie.

Para resolver, sugiro colocar o pacote do restfulie como menos prioridade do que os 3rd parties, porém, mais prioridade do que o outros da caelum.

O que acha?

Lucas_Cavalcanti

parece bom =)

Criado 4 de agosto de 2011
Ultima resposta 8 de ago. de 2011
Respostas 7
Participantes 2