Vraptor3: Forçando instanciação de objeto via converter

Tenho um converter para um objeto de paginação. Esse meu objeto de paginação nada mais é que um VO com os dados da página atual.

public class Paging { private int page; }

Meu converter:

[code]public Paging convert(String value, Class<? extends Paging> type, ResourceBundle bundle) {
if (value == null || value.trim().isEmpty()) {
return Paging.getInstance(); // create an empty paging
}

// create a paging with current page value
return Paging.getInstance(Integer.valueOf(value));

}[/code]

No meu controller eu uso basicamente assim:

@Path( { "/admin/user/", "/admin/user/page-{paging}/" }) public void list(Paging paging) { [...] }

Porém quando o URI for /admin/user/ esse objeto vem sempre nulo. Atualmente eu fico fazendo if para evitar nulos, mas eu quero poder inicializar esse objeto sempre, mesmo que o valor original seja nulo. Há como?

tem como sim… =) (pergunta difícil dessa vez heim garcia :P)

Tem um projeto paralelo que instancia os parâmetros… pra funcionar vc precisa criar o arquivo (ou colocar no seu customProvider):

@Component
public class CustomProvider extends SpringProvider {

	@Override
	protected void registerCustomComponents(ComponentRegistry registry) {
		registry.register(ParametersProvider.class, IogiParametersProvider.class);
		registry.register(Instantiator.class, VRaptorInstantiator.class);
	}
}

registrar isso no web.xml e colocar o iogi.jar no sistema (tá na pasta lib/optional do vraptor-core)

esse Iogi é bem melhor que o ognl em vários sentidos, mas ele não está totalmente estável. A gente usa em 2 projetos grandes e ainda não deu problemas… com ele os parâmetros são sempre instanciados…

outro jeito de fazer isso é descobrir um jeito de hackear o Ognl pra ele sempre instanciar os parâmetros… com o iogi é mais fácil :wink:

Lucas, acabou o round de perguntas difíceis, hehehe.

Hmm, eu tinha visto uma issue sobre o Iogi. Ele instancia tudo por padrão? Aí fico com uma dúvida… no caso se eu tiver um parametro Customer e no meu JSP uma propriedade customer.name ele sempre vai instanciar customer mesmo que name seja null? E no caso se eu nem sequer tiver o customer na tela mas tiver como parametro ele vai instanciar?

Abraços

sem problemas, pode fazer perguntas difíceis :wink: hehehe
ele faz a mesma coisa que o Ognl, mas usa uma estratégia melhor… Teoricamente ele tem o mesmo comportamento que o Ognl (tem vários testes no VRaptor pra garantir isso ;))

então sim… isso vai funcionar… caso não funcione me fale =)

Não achei o Instantiator.class. Estou com o vraptor baixado sexta-feira do github. 3.0.3-snapshot.

tá no iogi.jar… vc precisa colocar ele no seu WEB-INF/lib

Lucas, fiz os testes aqui e foi melhor que o esperado.

Notei que ele instancia automaticamente mesmo os parametros, e sempre chamando os converters se houverem. No caso do meu converter que passei no primeiro post ele chega com value == null, assim eu posso tratar da forma que eu quiser. No meu caso eu instancio a primeira página.

Quando chamei meu método edit(Long) passando o parametro como null ele então passou como nulo corretamente. Fiquei com medo dele passar um new Long(0) ou algo assim. Era o que eu esperava.

Só fiquei com dúvida se ele instancia sempre o objeto ou ele tenta apenas invocar o converter se existir. No caso, explicando melhor, se eu tiver um método store(Customer) onde customer for null, o Iogi mantém ele null ou instancia um new Customer()?

Ao tentar salvar um objeto estou tomando uma exception. Fazendo debug isso ocorre entre o post da página e antes de entrar no método.

As classes envolvidas são essas abaixo. Noto que em quase todas telas tudo funciona bem, porém essa aqui dá esse erro. Lucas, será que o Iogi está se perdendo em setar propriedades aninhadas?

[code]@Resource
public class MessageCenterController {

public void send(MessageDTO message) {
    result.onErrorUse(getClass()).editNew();

    messageService.sendMessage(message);
    result.use(Results.logic()).redirectTo(getClass()).list(MessageFolder.INBOX, null);
}

}[/code]

public class MessageDTO implements Serializable { private Long id; private UserDTO from; private UserDTO to; private UserDTO owner; private String subject; private String content; private Date sentDate; private boolean read; private MessageDTO related; }

SEVERE: StandardWrapperValve[default]: PWC1406: Servlet.service() for servlet default threw exception org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [java.lang.Long] is defined: no bean for this type registered at br.com.caelum.vraptor.ioc.spring.VRaptorApplicationContext.getBean(VRaptorApplicationContext.java:217) at br.com.caelum.vraptor.ioc.spring.SpringBasedContainer.instanceFor(SpringBasedContainer.java:61) at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator$VRaptorDependencyProvider.canProvide(VRaptorInstantiator.java:99) at br.com.caelum.iogi.DependenciesInjector.canObtainDependenciesFor(DependenciesInjector.java:20) at br.com.caelum.iogi.reflection.Target.canInstantiateOrInject(Target.java:111) at br.com.caelum.iogi.reflection.Target.compatibleConstructors(Target.java:101) at br.com.caelum.iogi.ObjectInstantiator.instantiate(ObjectInstantiator.java:44) at br.com.caelum.iogi.MultiInstantiator.instantiate(MultiInstantiator.java:21) at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.instantiate(VRaptorInstantiator.java:64) at br.com.caelum.vraptor.http.iogi.IogiParametersProvider.instantiateOrAddError(IogiParametersProvider.java:65) at br.com.caelum.vraptor.http.iogi.IogiParametersProvider.instantiateParameters(IogiParametersProvider.java:58) at br.com.caelum.vraptor.http.iogi.IogiParametersProvider.getParametersFor(IogiParametersProvider.java:45) at br.com.caelum.vraptor.interceptor. ParametersInstantiatorInterceptor.getParametersFor(ParametersInstantiatorInterceptor.java:83) at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:68) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:42) at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:41) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at esim.web.interceptor.NoCacheInterceptor.intercept(NoCacheInterceptor.java:49) at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:41) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at esim.web.security.SecurityUserSession.intercept(SecurityUserSession.java:105) at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:41) at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at esim.web.interceptor.CustomRequestExecution.execute(CustomRequestExecution.java:41) at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91) at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:55) at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:246) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096) at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:288) at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:647) at com.sun.enterprise.web.connector.grizzly.ssl.SSLReadTask.process(SSLReadTask.java:440) at com.sun.enterprise.web.connector.grizzly.ssl.SSLReadTask.doTask(SSLReadTask.java:228) at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:106)

então… o Iogi é uma sigla pra Immutable Object Graph Instantiator, ou seja, ele foi feito pra instanciar
objetos imutáveis. A consequencia disso é que ele tenta usar o construtor da sua classe que tem mais
argumentos (ele é espertinho e consegue descobrir como popular pelos parametros da requisição…)

E ele usa injeção de dependências nos seus parâmetros tb (vc pode receber daos nos seus parâmetros
e implementar um Active Record!)

E por enqto, qdo ele não consegue achar o parâmetro na requisição, ele tenta instanciar pelo container
do VRaptor… não achou a propriedade que é Long na requisição, e fez um container.instanceFor(Long.class)
que claramente não funciona…

pra corrigir isso, por enqto, vc tem que tirar os construtores, ou diminuir a visibilidade deles… (feio, eu sei =()
mas se for soh esse caso acho que não vai ter mto problema… vou tentar corrigir isso aqui assim que
possível…

Lucas, vou então seguir usando o provider tradicional por enquanto.

Abraços

=( ok… a gente só não colocou o Iogi como padrão pq ele tá meio instável… mas em breve ele vai estar estável e a gente vai fazer isso.

[]'s

Lucas, ressucitando o tópico… agora preciso mesmo converter os parametros mesmo que seja null. Como estão os trabalhos com o iogi, já dá para usar sem aquele erro?

[quote=Lucas Cavalcanti]pra corrigir isso, por enqto, vc tem que tirar os construtores, ou diminuir a visibilidade deles… (feio, eu sei =()
mas se for soh esse caso acho que não vai ter mto problema… vou tentar corrigir isso aqui assim que
possível…[/quote]

Então quer dizer que eu posso alterar meus DTOs e remover o contrutor que tem com o parametro Long, deixando apenas o default?

acho que esse erro ainda não foi corrigido no iogi =(

sem o construtor que recebe o long, ou adicionando um construtor padrão talvez funciona…

Lucas, eu não achei o site do projeto IOGI. Onde eu encontro ele?

Abraços

acho q o único site sobre o iogi por enquanto é esse:

Lucas, trocamos o OGNL pelo IOGI, estava indo tudo bem, precisamos corrigir algumas gambis que haviam sido criadas que o OGNL permitia.

Agora estamos com um problema.

Existe um parametro opcional no form que está sendo enviada como null e o IOGI dá erro porque não aceita null.

Isso é um BUG ou tem alguma forma de contornar?

qual é o tipo do parâmetro? vc está enviando o value “null”?

Tenho uma estrutura semelhante a esse exemplo:

public class Aluno {
   private Cpf cpf;
   
   // get e set 
}

public class Cpf {
  private String valor;

  public Cpf(String cpf) {
    valor = cpf;
  }
  
  // get
}

No request está sendo enviado aluno.cpf=""

O Cpf do aluno é opcional.

vc criou um converter pra cpf?

se não, tente trocar por aluno.cpf.cpf, que o iogi vai usar o construtor pra popular

O IOGI trabalha com os construtores (método padrão). Então você precisa criar os construtores com as possibilidades de campos que você tem na tela.

Ele tem um fallback que usa sets, porém quando você tem construtores com argumentos ele tenta usar esses construtores.

Mais ou menos assim. No meu caso eu fiz a primeira opção.