Vraptor 3.1.2 e bean validation [Resolvido]

Estou com os seguintes jars no classpath (hibernate-validator-4.0.1.GA.jar e validation-api-1.0.0.GA.jar), mas analisando o log, aparentemente o vraptor não chama o validador.


02/11/09 17:03:07 [DEBUG]  Invoking interceptor InstantiateInterceptor
02/11/09 17:03:07 [DEBUG]  Invoking interceptor ParametersInstantiatorInterceptor
02/11/09 17:03:07 [DEBUG]  Applying veiculo.placa with [xxx-0000]
02/11/09 17:03:07 [DEBUG]  Applying veiculo.ativo with [1]
02/11/09 17:03:07 [DEBUG]  Applying veiculo.transportadora.id with [1]
02/11/09 17:03:07 [DEBUG]  Found parameter names with paranamer for VeiculosController.save(Veiculo) as [veiculo]
02/11/09 17:03:07 [DEBUG]  Parameter values for [DefaultResourceMethod: VeiculosController.saveVeiculosController.save(Veiculo)] are [Veículo 0 placa: xxx-0000]
02/11/09 17:03:07 [DEBUG]  Invoking interceptor ExecuteMethodInterceptor
02/11/09 17:03:07 [DEBUG]  Invoking VeiculosController.save(Veiculo)
02/11/09 17:03:07 [DEBUG]  VRaptor ended the request

Código no controller


@Path("/veiculo/add")
public void save(Veiculo veiculo) {
	validator.validate(veiculo);
	validator.onErrorUse(logic()).forwardTo(getClass()).form();
	veiculos.add(veiculo);
	result.include("message", "Veículo adicionado com sucesso!");
	result.redirectTo(this).list();
}

e no meu model

@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Veiculo implements Audited{
	
	@Id
	@GeneratedValue
	private long id;
	
	@Pattern(regexp = "[A-Z]{3}-[0-9]{4}")
	private String placa;
	
	@OneToMany(mappedBy="veiculo", cascade = {CascadeType.ALL}, orphanRemoval = true)
	private List<Carga> cargas = new ArrayList<Carga>();
	
	@ManyToOne
	@JoinColumn(name = "transportadora_id")
	private Transportadora transportadora;

É preciso criar alguma implementação da interface BeanValidator e anotar com @Component ou o vraptor sabe delegar para alguma baseado nos jars do classpath?

Durante o startup do tomcat nenhuma mensagem de erro aparece no log (em DEBUG level)

o que esta faltando?

Hmm, você precisa fazer simplesmente injetar o Validator e depois chamar validator.validate. Você fez certo. Quando o Vraptor é inicializado ele procura pelas classes tanto do Bean Validator quanto do Hibernate Validator 3x e habilita quais ele encontrar.

Se você habilitar o debug do Vraptor notará a mensagem abaixo no seu console. Dê uma olhada nela.

Então Garcia, eu notei isso analisando o código fonte do vraptor.

Essa mensagem não aparece do log do startup. O engraçado é que em teoria o vraptor deveria passar para o DefautValidator o NullBeanValidator, se algum problema ocorresse, não é?

Mas a mensagem "You are willing to validate an object, but there is no bean validation engine registered. Please add the jars of some implementation of JSR 303 or Hibernate Validator." deveria ocorrer quando eu chamasse o validate, mas isso também não ocorre.

Mas os jars estão corretos pois eu consigo rodar este teste


public class VeiculosTest {

    private static Validator validator;

    @BeforeClass
    public static void setUp() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }

    @Test
    public void placaInvalida() {
       	
    	Veiculo veiculo = new Veiculo();
       	veiculo.setPlaca("X");

        Set<ConstraintViolation<Veiculo>> constraintViolations = validator.validate(veiculo);

        assertEquals(1, constraintViolations.size());
        assertEquals("must match \"[A-Z]{3}-[0-9]{4}\"", constraintViolations.iterator().next().getMessage());
        
    }

    
    @Test
    public void veiculoValido() {
    	
    	Veiculo veiculo = new Veiculo();
       	veiculo.setPlaca("MMM-1111");

        Set<ConstraintViolation<Veiculo>> constraintViolations = validator.validate(veiculo);

        assertEquals(0, constraintViolations.size());
        
    }
}

Estranho… muito estranho. Ele deveria mostrar algo.

Penso talvez alguma classe em um nível acima da sua aplicação possa estar escondendo algo. Você está com algum jar do vraptor dentro do container ao invés de estar na aplicação? Esses jars (hibernate-validator-4.0.1.GA.jar e validation-api-1.0.0.GA.jar) estão na sua aplicação ou no container. O correto é estarem todos na aplicação.

Uma coisa que você pode fazer para teste é rodar um controller que faça uma instanciação do bean validator factory com a aplicação UP.

[code]@Resource
public class ValidatorTestController {

@Path("/test")
public void test() {
System.out.println(Validation.buildDefaultValidatorFactory());
}
}[/code]

Estranho mesmo, os arquivos estão na aplicação (WEB-INF\lib)

criei a classe e executei o teste


@Resource
public class ValidatorTestController {
	
	
	@Path("/test")  
	public void test() {  
		
		ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
		Validator validator = factory.getValidator();
		
		Veiculo veiculo = new Veiculo();
       	veiculo.setPlaca("X");

        Set<ConstraintViolation<Veiculo>> violations = validator.validate(veiculo);
        
        System.out.println(violations.size());
        System.out.println(violations.iterator().next().getMessage());

	} 
	
} 

e a saída foi

02/11/09 18:57:00 [DEBUG]  trying to access /test
02/11/09 18:57:00 [DEBUG]  found resource [DefaultResourceMethod: ValidatorTestController.testValidatorTestController.test()]
02/11/09 18:57:00 [DEBUG]  Invoking interceptor FlashInterceptor
02/11/09 18:57:00 [DEBUG]  Invoking interceptor InterceptorListPriorToExecutionExtractor
02/11/09 18:57:00 [DEBUG]  Invoking interceptor NoCacheInterceptor
02/11/09 18:57:00 [DEBUG]  Invoking interceptor InstantiateInterceptor
02/11/09 18:57:00 [DEBUG]  Invoking interceptor ParametersInstantiatorInterceptor
02/11/09 18:57:00 [DEBUG]  Trying to make class for ValidatorTestController$test$1822909661$7
02/11/09 18:57:00 [DEBUG]  Found parameter names with paranamer for ValidatorTestController.test() as []
02/11/09 18:57:00 [DEBUG]  Parameter names found for creating type are: []
02/11/09 18:57:00 [DEBUG]  Methods: []
02/11/09 18:57:00 [DEBUG]  Fields: []
02/11/09 18:57:00 [DEBUG]  cached generic type for method [DefaultResourceMethod: ValidatorTestController.testValidatorTestController.test()]
02/11/09 18:57:00 [DEBUG]  Found parameter names with paranamer for ValidatorTestController.test() as []
02/11/09 18:57:00 [DEBUG]  Parameter values for [DefaultResourceMethod: ValidatorTestController.testValidatorTestController.test()] are []
02/11/09 18:57:00 [DEBUG]  Invoking interceptor ExecuteMethodInterceptor
02/11/09 18:57:00 [DEBUG]  Invoking ValidatorTestController.test()
1
must match "[A-Z]{3}-[0-9]{4}"
....

Ou seja, rolou…

Você tem os jars do Hibernate Validator 4x. Mas você tem os jars do Hibernate Validator 3x? Não precisa (e nem deve) ter o do 3x, mas penso que talvez possa haver algum conflito.

Estou usando aqui em um projeto em glassfishv3 e funcionando bem.

[quote=garcia-jj]Você tem os jars do Hibernate Validator 4x. Mas você tem os jars do Hibernate Validator 3x? Não precisa (e nem deve) ter o do 3x, mas penso que talvez possa haver algum conflito.

Estou usando aqui em um projeto em glassfishv3 e funcionando bem.[/quote]

Não, não tenho…

Se retiro o método da validação tudo funciona, testei em outros controllers, de outros projetos e acontece a mesma coisa.
O mais loco é que a requisição é processada até o fim, mas não é lançada nenhuma exception, nem é feito o redirect do result ou o forward do validator…

faz o seguinte teste:

receba no construtor de algum controller uma List (import do vraptor), e imprima a lista…

posta aqui o que veio…

Então Lucas, olha só o método do meu controller


@Path("/veiculo/add")
	public void save(Veiculo veiculo) {
		System.out.println(validators);
		for(BeanValidator validator : validators){
			validator.validate(veiculo);
			//validator.onErrorUse(logic()).forwardTo(getClass()).form();
		}
		veiculos.add(veiculo);
		result.include("message", "Veículo adicionado com sucesso!");
		result.redirectTo(this).list();
    }

e analisando a saída o validador correto é passado mas não valida o objeto

03/11/09 08:36:31 [DEBUG]  Trying to make class for VeiculosController$save$446443246$9
03/11/09 08:36:31 [DEBUG]  Found parameter names with paranamer for VeiculosController.save(Veiculo) as [veiculo]
03/11/09 08:36:31 [DEBUG]  Parameter names found for creating type are: [Veiculo]
03/11/09 08:36:31 [DEBUG]  Method for field 'Veiculo' being defined for type Lprixma/lotes/models/Veiculo;
03/11/09 08:36:31 [DEBUG]  Methods: [public void VeiculosController$save$446443246$9.setVeiculo(prixma.lotes.models.Veiculo), public prixma.lotes.models.Veiculo VeiculosController$save$446443246$9.getVeiculo()]
03/11/09 08:36:31 [DEBUG]  Fields: [private prixma.lotes.models.Veiculo VeiculosController$save$446443246$9.Veiculo_]
03/11/09 08:36:31 [DEBUG]  cached generic type for method [DefaultResourceMethod: VeiculosController.saveVeiculosController.save(Veiculo)]
03/11/09 08:36:31 [DEBUG]  Applying veiculo.transportadora.id with [1]
03/11/09 08:36:31 [DEBUG]  Found parameter names with paranamer for VeiculosController.save(Veiculo) as [veiculo]
03/11/09 08:36:31 [DEBUG]  Parameter values for [DefaultResourceMethod: VeiculosController.saveVeiculosController.save(Veiculo)] are [Veículo 0 placa: x]
03/11/09 08:36:32 [DEBUG]  Invoking interceptor ExecuteMethodInterceptor
03/11/09 08:36:32 [DEBUG]  Invoking VeiculosController.save(Veiculo)
[br.com.caelum.vraptor.validator.JSR303Validator@4a69ff]
03/11/09 08:36:32 [DEBUG]  VRaptor ended the request

Você pode usar esse snapshot do Vraptor ao invés do seu jar atual?

http://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.1.3-SNAPSHOT/vraptor-3.1.3-20100428.160403-2.jar

[quote=garcia-jj]Você pode usar esse snapshot do Vraptor ao invés do seu jar atual?

http://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.1.3-SNAPSHOT/vraptor-3.1.3-20100428.160403-2.jar[/quote]

Valeu Garcia, funcionou certinho, segue o log

03/11/09 13:02:24 [DEBUG]  Initializing JSR303 factory for bean validation
03/11/09 13:02:24 [DEBUG]  there are 1 violations at bean Veículo 0 placa: x.
03/11/09 13:02:24 [DEBUG]  added message must match "[A-Z]{3}-[0-9]{4}" to validation of bean Veículo 0 placa: x
03/11/09 13:02:24 [DEBUG]  Found parameter names with paranamer for VeiculosController.save(Veiculo) as [veiculo]
03/11/09 13:02:24 [DEBUG]  Executing VeiculosController.form()
03/11/09 13:02:24 [DEBUG]  Forwarding to /WEB-INF/jsp/veiculos/form.jsp
03/11/09 13:02:24 [DEBUG]  Deferring request to container: /frigorifico/WEB-INF/jsp/veiculos/form.jsp

Aproveitando o assunto, não seria legal modificar a interface Validator do vraptor para também aceitar o “this”, como no result

validator.onErrorUse(logic()).redirectTo(this).form();

e adicionar alguns atalhos também

validator.onErrorRedirectTo(this).form();

grato pela ajuda (Keep on Rockin’!)

vamos colocar esses atalhos no validator tb… =) só precisa ver nomes bons pra eles…

[quote=wpivotto][quote=garcia-jj]Você pode usar esse snapshot do Vraptor ao invés do seu jar atual?

http://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.1.3-SNAPSHOT/vraptor-3.1.3-20100428.160403-2.jar[/quote]

Valeu Garcia, funcionou certinho, segue o log[/quote][/quote]

Lucas, acho que isso é o caso do NPE quanto não é chamado o lazy-initializing do ValidatorFactory. Só achei estranho ele estar escondendo o NPE e seguindo o fluxo como se nada tivesse acontecido.