package br.com.teste;
// Vários imports
@Resource
@RequestScoped
public class UsuarioController {
private final Result result;
private final UsuarioDao dao;
public UsuarioController(Result result, UsuarioDao dao) {
this.result = result;
this.dao = dao;
}
@Get
@Path("/meuprojeto/{login}/perfil")
public void mostrarPerfil(String login) {
Usuario u = dao.procurarPorLogin(login);
// Várias coisas que faço com o usuário e/ou com o VRaptor.
}
@Post
@Path("/meuprojeto/urlqualquer/{login}")
public void outroMetodo(String login) {
Usuario u = dao.procurarPorLogin(login);
// Várias coisas que faço com o usuário e/ou com o VRaptor.
result.use(Results.logic()).redirectTo(UsuarioController.class).list(login);
}
// Outros métodos
}
@Get
@Path("/meuprojeto/{usuario.login}/perfil")
public void mostrarPerfil(Usuario usuario) {
// Várias coisas que faço com o usuário e/ou com o VRaptor.
}
@Post
@Path("/meuprojeto/urlqualquer/{usuario.login}")
public void outroMetodo(Usuario usuario) {
// Várias coisas que faço com o usuário e/ou com o VRaptor.
result.use(Results.logic()).redirectTo(UsuarioController.class).list(usuario);
}
@Get
@Path("/meuprojeto/{usuario}/perfil")
public void mostrarPerfil(Usuario usuario) {
// Várias coisas que faço com o usuário e/ou com o VRaptor.
}
@Post
@Path("/meuprojeto/urlqualquer/{usuario}")
public void outroMetodo(Usuario usuario) {
// Várias coisas que faço com o usuário e/ou com o VRaptor.
result.use(Results.logic()).redirectTo(UsuarioController.class).list(usuario);
}
package br.com.teste;
// Vários imports
@ApplicationScoped
@Convert(Usuario.class)
public class UsuarioConverter implements Converter<Usuario> {
private final UsuarioDao dao;
public UsuarioConverter(UsuarioDao dao) {
this.dao = dao;
}
public Usuario convert(String value, Class<? extends Usuario> type, ResourceBundle bundle) {
return dao.procurarPorLogin(value);
}
}
No entanto, quando eu uso o metodo outroMetodo, que tem um redirectTo, o VRaptor gera umas URLs assim:
/meuprojeto/br.com.teste.Usuario@45f7e2/perfil
Apesar de a conversão de ida String->Usuario ter usado o Converter, a conversão de volta Usuario->String sempre usa o método toString().
Utilizar o método toString() sempre é muito restritivo, pois ele já é utilizado para outras finalidades.
Para contornar este problema, existem algumas soluções possíveis. Mas todas elas são meio gambiarrosas.
A primeira delas é criar um Router herdando de DefaultRouter e sobreescrever o método urlFor por um quase idêntico, mas com uma diferença:return matches.next().urlFor(type, method, creator.instanceWithParameters(resourceMethod, params));
String toReturn = matches.next().urlFor(type, method, creator.instanceWithParameters(resourceMethod, params));
for (Object param : params) {
if (param instanceof Usuario) toReturn = toReturn.replace(param.toString(), ((Usuario) param).getLogin());
}
return toReturn;
Para tentar fazer um código menos gambiarroso, analisamos que a variável matches é do tipo Iterator<Route> e a implementação concreta de Route é FixedMethodStrategy.
O Iterator<Route> é criado pela classe PathAnnotationRoutesParser, que por sua vez utiliza a RouteBuilder. RouteBuilder instancia a FixedMethodStrategy, injetando nela uma instância de DefaultParametersControl.
O método fillUri(Object) de DefaultParametersControl utiliza o método toString() e é aí que é a origem do problema.
A classe PathAnnotationRoutesParser está fortemente acoplada a RouteBuilder, que por sua vez está fortemente acoplada a FixedMethodStrategy e a DefaultParametersControl, o que significa que substituir a implementação de alguma destas classes por outra coisa é algo difícil.
Uma outra possibilidade mais atraente para resolver isso sem precisar desta gambiarra seria criar uma espécie de decorator de Route e fazer o matcher conter instâncias apenas do decorator. Mas isso continua sendo algo trabalhoso.
Então vem a minha pergunta: Estamos usando o VRaptor de uma forma inadequada ou não prevista? Caso seja inadequada, eu devo me contentar em receber apenas Strings e números como parâmetros extraídos da URL e devo deixar coisas mais complexas apenas para dados de formulários? Caso contrário, gostaria de sugerir uma nova interface para um "Converter reverso", e então o meu converter ficaria assim:package br.com.teste;
// Vários imports
@ApplicationScoped
@Convert(Usuario.class)
public class UsuarioConverter implements Converter<Usuario>, ReverseConverter<Usuario> {
private final UsuarioDao dao;
public UsuarioConverter(UsuarioDao dao) {
this.dao = dao;
}
public Usuario convert(String value, Class<? extends Usuario> type, ResourceBundle bundle) {
return dao.procurarPorLogin(value);
}
public String reverseConvert(Usuario usuario, ResourceBundle bundle) {
return usuario.getLogin();
}
}


