Transformer Commons Collections
L'utilisation de Transformer
, interface org.apache.commons.collections4.Transformer
, va permettre d'effectuer des transformation d'objets. Cette interface définie la fonction transform
qui retourne l'instance transformée dans une nouvelle classe ou la même.
Votre avis
Nobody voted on this yet
|
|
Implémentation
Dans le cadre de cette étude, une première implémentation est mise en place afin de transformer une instance de People
en chaîne de caractères avec la concaténation du prénom et nom.
package fr.ejn.tutorial.apache.commons.collections4.transformer;
import fr.ejn.tutorial.datas.People;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.lang3.StringUtils;
/**
* Sample transformer used to buld the people name.
*
* @author Etienne Jouvin
*
*/
public class PeopleNameTransformer implements Transformer<People, String> {
/** {@inheritDoc} */
@Override
public String transform(People input) {
return null == input ? StringUtils.EMPTY : String.format("%s %s", input.getName(), input
.getSurname());
}
}
La fonction transform
teste que l'argument n'est pas null, permettant de s'affranchir les NullPointerException
, et construit la chaîne de caracteres avec le prénom et nom.
Transformation liste
Les instances de Transformer
permettent de modifier les éléments. Ils sont utilisés dans les fonctions de sélection des différents utilitaires. Un exemple est implémenté dans le test unitaire fr.ejn.tutorial.apache.commons.collections4.transformer.PeopleNameTransformerTest
.
package fr.ejn.tutorial.apache.commons.collections4.transformer;
import fr.ejn.tutorial.datas.Gender;
import fr.ejn.tutorial.datas.People;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Transformer;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class PeopleNameTransformerTest {
private Transformer<People, String> instance;
@Before
public void setUp() throws Exception {
instance = new PeopleNameTransformer();
}
@Test
public void testTransform() {
People people = new People();
people.setName("Etienne");
people.setGender(Gender.MAN);
people.setSurname("Jouvin");
List<People> peoples = new ArrayList<People>(3);
peoples.add(people);
// Add a null to test transform on null.
peoples.add(null);
people = new People();
people.setName("Mother");
people.setGender(Gender.WOMAN);
people.setSurname("Jouvin");
peoples.add(people);
Collection<String> actual = CollectionUtils.collect(peoples, instance);
Assert.assertNotNull("Validate result is not null", actual);
Assert.assertEquals("Validate result size", 3, actual.size());
Assert.assertEquals("Etienne Jouvin", IterableUtils.get(actual, 0));
Assert.assertEquals("", IterableUtils.get(actual, 1));
Assert.assertEquals("Mother Jouvin", IterableUtils.get(actual, 2));
}
}
Dans un premier temps, une liste est créé avec différents éléments. Puis la fonction collect
de la classe CollectionUtils
est exécutée sur la liste avec une instance du Transformer
. Ainsi, une nouvelle collection est créée avec les chaînes de caractères. A noter qu'aucun filtre n'est appliqué sur la collection, et les nulls sont traités.
Le test unitaire valide le contenu de la nouvelle collection, avec les chaînes de caractères attendues.
Combinaison transformation / filtre
Dans les exemples précédents, seule la transformation des données est explicitée. Cependant il peut être parfois d'effectuer deux opérations en une seule étape, comme transformer les données et de ne pas collecter certains résultats de la transformation. Pour cela, il faut combiner l'utilisation d'un Predicate et une instance de Iterable
qui va effectuer la transformation à la volée. Toute l'astuce se situe dans cette dernière instance qui est retournée par la fonction transformedIterable
de la classe IterableUtils
.
Le test unitaire testPredicateTransform
, dans la classe CollectionUtilsTest
, démontre cette utilisation.
@Test
public void testPredicateTransform() {
People people = new People();
people.setName("Etienne");
people.setGender(Gender.MAN);
people.setSurname("Jouvin");
List<People> peoples = new ArrayList<People>(3);
peoples.add(people);
// Add a null to test transform on null.
peoples.add(null);
people = new People();
people.setName("Mother");
people.setGender(Gender.WOMAN);
people.setSurname("Jouvin");
peoples.add(people);
// Create an iterable with the transformer instance.
Iterable<String> peoplesNamesIterable = IterableUtils
.transformedIterable(peoples, new PeopleNameTransformer());
// Create a predicate to filter on Empty String.
Predicate<String> emptyValuePredicate = PredicateUtils.equalPredicate(StringUtils.EMPTY);
Predicate<String> notEmptyValuePredicate = PredicateUtils.notPredicate(emptyValuePredicate);
Collection<String> peoplesNames = CollectionUtils
.select(peoplesNamesIterable, notEmptyValuePredicate);
Assert.assertNotNull("Validate collection is not null", peoplesNames);
Assert.assertEquals("Validate collection size", 2, peoplesNames.size());
Assert
.assertEquals("Validate first name", "Etienne Jouvin", IterableUtils.get(peoplesNames, 0));
Assert.assertEquals("Validate first name", "Mother Jouvin", IterableUtils.get(peoplesNames, 1));
// Use the selectRejected
peoplesNames = CollectionUtils.selectRejected(peoplesNamesIterable, emptyValuePredicate);
Assert.assertNotNull("Validate collection is not null", peoplesNames);
Assert.assertEquals("Validate collection size", 2, peoplesNames.size());
Assert
.assertEquals("Validate first name", "Etienne Jouvin", IterableUtils.get(peoplesNames, 0));
Assert.assertEquals("Validate first name", "Mother Jouvin", IterableUtils.get(peoplesNames, 1));
}
Dans cet exemple, le transformer PeopleNameTransformer
est utilisé. Or il retourne StringUtils.EMPTY
lorsque l'objet est null
. C'est cette valeur qui doit être filtrée.
La fonction equalPredicate
de la classe PredicateUtils
permet de mettre en place un Predicate qui valide l'objet si il est égal à une valeur, et donc à StringUtils.EMPTY
. Or il est souhaité de les filtrer et non pas les récupérer. Le Predicate est alors combiné avec une instance retournée par la fonction notPredicate
de PredicateUtils
. Cette dernière retourne l'inverse du Predicate encapsulé.
Il faut ensuite parcourir la collection d'origine et transformer les données. Il serait possible d'effectuer une première passe pour la transformation, puis une seconde pour effectuer le filtre. Mais cela implique deux parcours de la liste. Or, la fonction transformedIterable
de la classe IterableUtils
permet de construire une instance Iterable
qui retourne les valeur transformée de la collection source. En utilisant cette isntance lors de l'appel à la fonction select
de CollectionUtils
avec le Predicate construit, seule les transformations non nulles des instances People
sont stockées dans une nouvelle collection.
Le deuxième exemple permet de s'affranchir du Predicate notPredicate
, en utilisant la fonction selectRejected
.