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

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?

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

[code]
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

[/code]=======================================

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

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.

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

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:

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

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

[code]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());
	
}

}[/code]

[code]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 Serializer from(T object) {
    return null;
    }

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

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

}[/code]

[code]package br.com.caelum.vraptor.serialization;

import java.util.Comparator;

final class PackageComparator implements Comparator {
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);
}

}[/code]

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

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?

parece bom =)