Convertisseurs d’objets

Il est parfois nécessaire de convertir une instance d’un type source <S> vers un type destination <T> alors que ces types ne sont pas connus au moment de la compilation. Divers projets (Apache Common Convert, Spring, etc.) ont créé leur propres interfaces pour effectuer des conversions d’objets entre des types connus seulement au moment de l’exécution. Les détails varient, mais ces interfaces ressemblent typiquement à l’interface suivante:

interface ObjectConverter<S,T> {   // Certains projets utilisent seulement "Converter" comme nom d’interface.
    T apply(S object);             // Un autre nom de méthode souvent utilisé par les autres projets est "convert".
}

Comme d’autres projets, Apache SIS définit sa propre interface ObjectConverter. La principale différence entre l’interface de SIS est celle que l’on retrouve dans d’autres projets est que SIS fournit des informations à propos de certaines propriétés mathématiques des convertisseurs. Un convertisseur de Apache SIS peut avoir aucune, une ou plusieurs des propriétés suivantes:

Injective
Une fonction est injective si aucune paire de valeurs de S ne peut produire la même valeur de T.

Exemple: la conversion IntegerString effectuée par Integer.toString() est une fonction injective car si deux valeurs de type Integer ne sont pas égales, alors il est garanti que leurs conversions produiront différentes valeurs de String. En revanche la conversion StringInteger effectuée par Integer.valueOf(String) n’est pas une fonction injective parce que plusieurs valeurs distinctes de type String peuvent être converties vers la même valeur de type Integer. Par exemple les conversions des chaînes de caractères "42", "+42" et "0042" donnent toutes la même valeur entière 42.

Surjective
Une fonction est surjective si chaque valeur de T peut être produite à partir d’au moins une valeur de S.

Exemple: la conversion StringInteger effectuée par Integer.valueOf(String) est une fonction surjective car chaque valeur de type Integer peut être produite à partir d’un moins une valeur de String. En revanche la conversion IntegerString effectuée par Integer.toString() n’est pas une fonction surjective parce qu’elle ne peut pas produire toutes les valeurs possibles de type String. Par exemple il n’y a aucun moyen de produire la valeur "ABC" avec la méthode Integer.toString().

Bijective
Une fonction est bijective s’il y a une relation de un-à-un entre les valeurs de S et de T.

Note: la propriété bijective est définie ici pour des raisons de clarté, mais en fait n’a pas d’item explicite dans l’énumération FunctionProperty de Apache SIS. Ce n’est pas nécessaire puisqu’une fonction qui est à la fois injective et surjective est nécessairement bijective.

Préservant l’ordre
Une fonction préserve l’ordre si toute séquence de valeurs S croissantes correspond à une séquence de valeurs T croissantes.

Exemple: la conversion du type Integer vers Long préserve l’ordre naturel des éléments. Toutefois la conversion du type Integer vers String ne préserve pas l’ordre naturel, parce que des séquences des nombres entiers croissants ont un ordre différents lorsque les chaînes de caractères sont classées par ordre lexicographique. Par exemple 1, 2, 10 devient "1", "10", "2".

Renversant l’ordre
Une fonction renverse l’ordre si toute séquence de valeurs S croissantes correspond à une séquence de valeurs T décroissantes.

Exemple: une conversion qui inverse le signe des nombres.

Ces informations peuvent sembler inutiles lorsque l’on convertit des valeurs sans tenir compte du contexte où elles apparaissent. Mais lorsque la valeur à convertir fait parti d’un objet plus gros, alors ces informations peuvent impacter la façon dont la valeur convertie sera utilisée. Par exemple la conversion d’une plage de valeurs représentée par [minmax] est directe lorsque la fonction de conversion préserve l’ordre. Mais si la fonction de conversion renverse l’ordre, alors les valeurs minimale et maximale doivent être interchangées. Par exemple si la fonction de conversion inverse le signe des valeurs, alors la plage convertie sera [-max … -min]. Si la fonction de conversion ne préserve ni ne renverse l’ordre, alors la plage de valeurs ne peut pas être convertie du tout (parce qu’elle ne contiendrait plus le même ensemble de valeurs) même si les valeurs individuelles auraient pu être converties.