Bean validation avec camel: Composant camel-bean-validator

L'objet de ce billet est de présenter la validation (jsr303) avec le composant camel-bean-validator.

camel-logo.png

Ce composant permet de valider des pojos ou beans annotés.

Deux démos sont fournies. La seconde un peu plus avancée.

Chaque démo est un projet maven réalisée en trois actes:

- Configurer la pom,

- Annoter le bean,

- Tester avec JUnit.

Voici dons les étapes.

PREMIERE PARTIE: Valider des beans

ACTE1. Dépendances du pom

<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-bean-validator</artifactId>
<version>2.10.2</version>
</dependency>

La version doit être celle de camel-core.

ACTE2. Ecrire un bean annoté pour validation

package fr.netapsys.camel.beans;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
public class Utilisateur {
	@NotNull private String login;
	@Pattern(regexp="[a-zA-Z0-9]+")
	private String pwd;

        public Utilisateur(){}
	
	public Utilisateur(String login,String pwd){
	  setLogin(login);
	  setPwd(pwd);
	}

... omis setters/getters et toString
}

ACTE3. Tester et déclarer la route

package fr.netapsys.camel.tests;

import org.apache.camel.*;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.bean.validator.*;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.netapsys.camel.beans.Utilisateur;

public class TestCamelUtilisateurValidator 
                        extends CamelTestSupport {

 private static final String ENTREE = "direct:in";	
  private static final Logger logger=
        LoggerFactory.getLogger(TestCamelUtilisateurValidator.class);
  //Route definie ici en surchargeant 
   //createRouteBuilder de CamelTestSupport.
  @Override
   protected RouteBuilder createRouteBuilder() 
                  throws Exception {
     return new RouteBuilder() {
	@Override
	public void configure() throws Exception
	{
 	   onException(BeanValidationException.class)
	    .handled(false)
            .log(LoggingLevel.ERROR,
                 ">>>Error in:  ${body},\nmsg=${exception.message}\n")
	    .end();
			 	
	  from(ENTREE)
		.to("bean-validator://v")
		.convertBodyTo(String.class)
		.setHeader(Exchange.FILE_NAME,constant("ok.log"))
		.to("file:/temp")
		.end();
		}
	 };
	}

  @Test
  public void testOk() throws Exception {
		
	ProducerTemplate producerTemplate =
                     context.createProducerTemplate();
	Utilisateur user = new Utilisateur("test","secret");
	logger.info("body ok :"+user);
		
	producerTemplate.sendBody(ENTREE, user);
         //assertion todo
         //dans /temp le fichier ok.log est créé
	}

  @Test
  public void testValidKo() throws Exception {
	ProducerTemplate producerTemplate = 
                context.createProducerTemplate();
	Utilisateur user = new Utilisateur();
	user.setLogin(null); //not correct
		
	Endpoint ep=context.getEndpoint(ENTREE);
	Exchange exch=ep.createExchange(ExchangePattern.InOnly);
	exch.getIn().setBody(user);
	Exchange out=producerTemplate.send(ep,exch);
	//pliz note this assert depends on errorHandler and handled.
	assertTrue(
            "Lorsque handled(false), BeanValidationException levée",
           out.getException() instanceof BeanValidationException);
      }
}

Explications:

La route camel est définie dans le test en surchargeant la méthode createRouteBuilder() de CamelTestSupport.

Cette route permet de stocker les messages valides dans un fichier et de logguer en erreur les messages non valides.

Deux méthodes de test :

- La première, testOk(), fait opérer la validation sur des données valides,

- La seconde testValidKo() permet de voir la propagation d'une BeanValidationException sur des données non valides.

Enfin, les commentaires dans le code du test détaille le fonctionnement du composant et l'interception de l'exception générée.

SECONDE PARTIE: Valider des listes de beans

ACTE1. Annoter le bean

Ici nous écrivons une classe, nommée Groupe, conteneur de beans Utilisateur.

La classe Groupe est annotée avec @Valid de javax.validation.

package fr.netapsys.camel.beans;
import java.util.*;
import javax.validation.Valid;
public class Groupe {
	@Valid
	private List<Utilisateur> users;
 	public Groupe(){
	 users=new ArrayList<>();
 	}
 	//methode pratique
	public void addUser(Utilisateur u){
		users.add(u);
	}
	...omis getters/setters
}

ACTE2. Tester

Ajouter à la classe de test la méthode testValidGroupeKo:

@Test
public void testValidGroupeKo()  {
 //preparer le body
  Groupe groupe=new Groupe();		
  Utilisateur user = new Utilisateur("anonym","anonym");
  groupe.addUser(user);
  
  user = new Utilisateur("anonym","--");
  groupe.addUser(user);

   //setter le body de l'exchange
   Endpoint ep=context.getEndpoint(ENTREE);
   Exchange exch=ep.createExchange();
   logger.info("Bad groupe utilisatuers :"+groupe);
   exch.getIn().setBody(groupe);
   //envoi de l exchange
   ProducerTemplate producerTemplate = 
            context.createProducerTemplate();
   Exchange out=producerTemplate.send(ep,exch);

   //assertion
   assertTrue(" BeanValidationException est levée", 
       out.getException() instanceof BeanValidationException);
}

Les commentaires du code explique la démarche de validation d'un conteneur d'objets.

En résumé, le conteneur doit comporter l'annotation @Valid et ses éléments doivent également être annotées avec javax.validation.constraints.

Nous avons réalisé la validation des beans et des conteneurs de beans avec une ou deux annotations et presque une ligne de code.

Voilà c'est tout!

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.