IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

Validation de données


Sujet :

Entrée/Sortie Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau candidat au Club
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    1
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 1
    Par défaut Validation de données
    Bonsoir,

    Je viens vers la communauté de Developpez pour avoir des avis, voire des nouvelles pistes ? Je recherche un moyen de simplifier la validation de données entrées par l'utilisateur sur la plateforme Java.

    La JSR 303 reprend bien ce besoin ; on peut ainsi voir deux dominants Hibernate Validator et OVal qui se ressemblent pour beaucoup mais avec quelques possibilités en plus pour OVal. Ces deux API fonctionnent par le biais d'annotations ou de déclaration par XML et les contraintes personnalisées sont envisageables.

    Ma question est donc ... passerai-je à côté d'une API plus simple / complète remplissant les mêmes fonctionnalités ?

    N'hésitez pas à partager votre avis sur le sujet.

    Merci d'avance,
    Spot.

  2. #2
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Par défaut
    La classe Pattern et des "if" ne te suffise pas ?

    Si tu veux quelque chose d'un peu propre, regroupe les entrées dans une classe (ex: Form), créer une interface (ex: Validator) avec une méthode de contrôle (ex: boolean validate(Form)), ensuite créer des instances de validator que tu relies (ex: soit dans une List<Validator>, soit par chaînage - méthode Validator next() dans l'interface Validator)
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

  3. #3
    Membre à l'essai
    Homme Profil pro
    Consultant Télécom
    Inscrit en
    Avril 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Consultant Télécom
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 6
    Par défaut
    Bonsoir à tous,

    Je profite de l'existence de ce fil de discussion pour poster ma question, qui relève en partie de la compréhension des I/O en Java.

    J'aimerais savoir comment généraliser une petite méthode qui me permettrait, côté serveur, de m'assurer que je reçois bien un Integer, par exemple.
    Voici ce que ça donne en mode console, avec invite de commande au clavier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public Integer putInteger() throws NumberFormatException, IOException{
    br = new BufferedReader(new InputStreamReader(System.in));
    mySecureInteger = new Integer(0);
    try {
    	inputLine = br.readLine();
    	setMySecureInteger(Integer.parseInt(inputLine)) ; 
    } catch(NumberFormatException nfe){
    	System.out.println("Invalid entry. ");
    	System.out.print("Please try again here >> ");
    	putInteger() ; 
    } catch (IOException ioe) {
    	System.err.println("IO error trying to read an Integer.");
    	ioe.printStackTrace();
    }
    return mySecureInteger ; 
    }
    Je ne maîtrise pas encore les notions autour des StringBuffer, InputStream et autres, mais je me suis dit que j'allais tenter de généraliser la forme de cette méthode ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public  Integer putInteger(InputStream in) throws NumberFormatException, IOException{
    br = new BufferedReader(new InputStreamReader(in));
    mySecureInteger = new Integer(0);
    try {
    	System.out.println("trying to read a String");
    	inputLine = br.readLine();
    	System.out.println("trying to parse an Integer");
    	setMySecureInteger(Integer.parseInt(inputLine)) ; 
    } catch(NumberFormatException nfe){
    	System.out.println("Invalid entry. ");
    	System.out.print("Please try again here >> ");
    	putInteger(in) ; 
    } catch (IOException ioe) {
    	System.err.println("IO error trying to read an Integer.");
    	ioe.printStackTrace();
    }
    return mySecureInteger ; 
    }
    Dans le main de la classe de validation, j'ai donc quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    System.out.println("Secure Input Testing Unit");
    		System.out.println("===================================");
    System.out.print("Please enter an integer here : ");
    InputStream in;
    in = new InputStream() {
     
    	@Override
    	public int read() throws IOException {
    		System.out.println("about to read");
    		System.in.read();
    		System.out.println("has read");
    		return 0;
    	}
    };
    Integer aSecureInteger = si_s.putInteger(in); //si_s est une instance de la classe de validation
    System.out.println("You entered : "+ aSecureInteger);
    Mais ça, ça ne fonctionne pas (d'où les println un peu partout pour tenter de comprendre ce qu'il se passe). Je confirme que je souhaite écrire une méthode sous une forme assez générale pour qu'elle puisse valider certains types indépendamment du choix du flux d'entrée.

    Merci pour votre aide et vos redirections éventuelles !

    (ps : j'ai lu deux trois pages sur JSR 303, mais je ne suis pas parvenu à utiliser la solution proposée par cette spécification ;
    pi : je suis nouvel inscrit sur ce site)

  4. #4
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Par défaut
    Bienvenu à toi.
    Pour commencer, on t'aidera même si tu es nouveau, ce forum est fait pour aider pas pour trier les gens sur le volet Sinon on voit que tu es nouveau à ton score (sur le côté gauche sous ton pseudo) ou alors c'est que tu as très mauvaise réputation :p

    Les flux en Java se décompose en deux types : les flux binaires (InputStream) et textes (Reader). Les flux textes reposent sur du binaire mais te permet de le traiter comme du texte sans te soucier des transformations (autre que l'encodage).

    La classe String est dîte immuable, c'est-à-dire qu'on ne peut modifier sa valeur. StringBuffer / StringBuilder sont des classes qui permettent de construire des chaînes de caractère dynamiquement (ajouter / suppression / modification de caractères), notamment lors de la lecture de flux texte.

    Quand tu utilises InputStreamReader, il est fortement conseillé de spécifier l'encodage. Car par défaut il utilise celui de ton système (exemple Cp1252 sur Windows). Quand tu lis un flux depuis l'entrée standard (System.in) généralement ce n'est pas trop grave mais dans le cadre de fichier (et si l'entrée standard est un fichier) tu risques d'avoir des surprises avec les caractères qui sortent de la plage ASCII.

    Ensuite, évite autant que possible (c'est toujours évitable moyennant parfois quelques pirouettes) d'utiliser la récursivité (rappeler la même méthode). Utilises plutôt des boucles. Et enfin prévoit également un cas "normal" pour sortir de ta boucle.
    En plus ton code créé à chaque fois un nouveau Reader. En plus readLine() peut renvoyer null s'il n'y a plus rien à lire sur le flux.

    Autre chose encore il vaut mieux contrôler la saisie à l'aide d'une expression régulière par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Pattern.compile("\\d").matcher().matches()
    . La levée d'exception étant plutôt coûteuse.


    EDIT : J'en ai oublié l'essentiel ! C'est quoi le problème ? Qu'est-ce qui ne fonctionne pas ?
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

  5. #5
    Membre à l'essai
    Homme Profil pro
    Consultant Télécom
    Inscrit en
    Avril 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Consultant Télécom
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 6
    Par défaut
    Nemek,

    Merci pour tes remarques sur les flux et sur l'encodage. Je n'en étais pas encore à me poser la question, mais je pense que ça me servira. Côté String et StringBuffer, je suis familier du sujet mais pas encore expérimenté. J'y reviendrai probablement.

    Par rapport à mes bouts de code, je suis conscient qu'ils soulèvent de nombreuses questions.

    Discussion hors-sujet initial

    Concernant l'algorithme même [ça sort du sujet initial], je veux bien discuter les éléments sur la récursivité. Je parlais de validation côté serveur, mais dans sa forme de base, la méthode est plus adaptée à une validation côté client (même si elle ne sera probablement pas en Java, mais plutôt en javascript). En effet, l'idée initiale, c'est de demander à l'utilisateur d'entrer un type spécifique au clavier et de le lui demander tant qu'il ne le fait pas. Pour ça, on essaie d'identifier le type en question dans le String qu'il saisit. Si l'identification de ce type est impossible (ie. ), on gère l'exception en lui redemandant la saisie. Ma question : pourquoi est-ce une mauvaise pratique de passer par les exceptions et par une récursivité ? je conçois bien le côté coûteux de la chose (c'est largement optimisable). On m'a conseillé d'éviter justement les boucles (notamment le do while, avec un booléen dans le while - ce que j'avais fait avant le try catch) sur ce genre de choses, car on se rapproche alors un peu trop du procédural. Et d'une certaine façon, on perd en lisibilité au sens "Java" du terme. N'y a-t-il pas un certain "juste" milieu entre ce qu'on ferait en C et la levée d'exceptions en Java ?

    Position du problème.

    Je cherche à écrire une classe de validation côté serveur. Elle contient des méthodes qui permettent de s'assurer que les objets que le serveur reçoit du client par la Socket sur l'ObjectInputStream (ou sur un autre flux entrant que j'utiliserai) sont des instances des classes attendues.

    Comment j'ai commencé à le traiter.

    J'ai écrit une classe de validation des entrées au clavier en ligne de commande pour quelques types presque primitifs. C'est pour ça que c'est un peu moche, notamment avec le BufferedReader instancié à chaque validation.(C'est aussi la raison d'être du System.in). Tel quel, ça fonctionne, dans le main de la classe de validation.

    Ensuite (et c'est là que ça ne fonctionne plus), j'ai cherché à le faire en imaginant la problématique côté serveur : je ne recevrai plus d'infos par l'entrée standard, mais je veux être capable de valider un type sur n'importe quel type de flux entrant. Donc autant écrire la forme la plus générale possible, et prendre en paramètre de la méthode de validation un flux. Ni une, ni deux, je change en InputStream, et par la même occasion, quand j'instancie ce dernier dans le main, l'IDE me fait automatiquement réécrire la méthode read()(cf. @override). Pour tester, je dis alors que read() se comporte tout comme . Et c'est là que je vois que je ne suis pas parvenu à écrire une forme générale qui permette notamment de faire de la validation au clavier (d'où finalement les quelques println placés çà et là pour voir où ça bloque).

    Au niveau de la console, voici ce qui se passe [EDIT : je précise : le processus ne termine pas].
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Secure Input Testing Unit
    ===================================
    Please enter an integer here : trying to read a String
    about to read
    12
    has read
    about to read
    has read
    about to read
    has read
    about to read
    has read
    about to read
    Cela paraît-il plus clair ?
    Merci

  6. #6
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Par défaut
    Les exceptions nécessitent des mécanismes particulier et une fois levée nécessitent certains calcul comme la StackTrace (pile d'appel).

    La récursivité c'est pas anodin, ca prend de la place. Ca crée une nouvelle frame sur la pile. Alors qu'une boucle while te coute rien en mémoire dans ton cas. La récursivité est également dangereuse si les conditions d'arrêt sont mal posées.

    "Tu n'identifies aucun type" (Je préfère parler de format) autre que celui d'un entier. Pourquoi ne pas vérifier s'il s'agit bien d'un entier avec de le transformer ?

    Dans un langage Objet, les blocs sont "procéduraux". Les structure de contrôle while sont là pour être utilisées. Pour ma part c'est en récursivité qu'on perd de la lisibilité sauf algorithme dont l'implémentation naïve est récursive.
    Là si tu disais que tu fais ta méthode ca donne : "On demande à l'utilisateur de saisir une valeur tant qu'elle n'est pas correcte".

    Pour la validation serveur, il faut savoir s'il s'agit de données textes ou binaire ... Si c'est binaire t'as aucune notion de format autre que la taille. Par exemple pour lire un int binaire, il faut 4 octets tant qu'ils sont là c'est un "int" valide. En revanche en mode texte tu es limité à certaines séries d'octet en fonction de l'encodage.

    Pourquoi créer une nouvelle instance de InputStream si tu utilises System.in ?_? System.in est un InputStream.
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

  7. #7
    Membre à l'essai
    Homme Profil pro
    Consultant Télécom
    Inscrit en
    Avril 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Consultant Télécom
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 6
    Par défaut
    Entendu, pour tes propos sur les exceptions et la récursivité. J'irai développer ces arguments auprès des Monsieurs Java qui m'entourent ces temps-ci.

    Là si tu disais que tu fais ta méthode ca donne : "On demande à l'utilisateur de saisir une valeur tant qu'elle n'est pas correcte".
    c'est exactement comme ça que je l'avais implémenté avant qu'on me dise "coucou, c'est pas propre, tu devrais pas te passer des exceptions dans ce cas."


    Pour la validation serveur, il faut savoir s'il s'agit de données textes ou binaire ... Si c'est binaire t'as aucune notion de format autre que la taille. Par exemple pour lire un int binaire, il faut 4 octets tant qu'ils sont là c'est un "int" valide. En revanche en mode texte tu es limité à certaines séries d'octet en fonction de l'encodage.
    Merci d'avoir redéveloppé ça, je comprends mieux (ça fait appel à de lointains TP).

    Pourquoi créer une nouvelle instance de InputStream si tu utilises System.in ?_? System.in est un InputStream.
    Je comprends que System.in est un InputStream. À ce stade du code, je veux juste tester si ma façon de l'écrire le rend notamment compatible avec l'InputStream particulier qu'est System.in. Mais demain, l'@override dans la méthode read() sera différent. C'est comme ça que je l'imagine.
    Ce que je veux dire, c'est que là où je suis rendu, je ne connais pas du tout les bonnes pratiques, que ce soit en termes de conception ou en termes de langage. Donc il n'y a pas forcément de logique que je cherche à défendre absolument dans ma façon de faire. J'ai encore beaucoup à apprendre, ne serait-ce qu'en conception...

    Merci encore, Nemek, pour tes réactions.

  8. #8
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Par défaut
    Je comprends pas le rapport entre le fait que System.in est une instance parmi tant d'autre d'InputStream et la classe anonyme que tu créés qui ne sert à rien et n'est pas optimale.

    Si tu utilises InputStream comme marquer dans sa documentation, alors ca marchera pour tous les InputStream. Les implémentations fournies par la JRE respectent l'interface, donc elles fonctionneront avec ton code.
    Si une implémentation ne fonctionne pas, le problème est dans l'implémentation pas dans l'algo qui l'utilise.
    C'est un principe que tu devrais garder en tête. Pense générique, test. Si ca fonctionne pas dans des cas particuliers vérifient si c'est ton algo ou les spécificités qui sont mal codées.

    Surtout que toutes les méthodes d'InputStream ne convergent pas nécessairement vers la méthode read().
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

  9. #9
    Membre à l'essai
    Homme Profil pro
    Consultant Télécom
    Inscrit en
    Avril 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Consultant Télécom
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 6
    Par défaut
    @Nemek,

    Entendu, je commence à saisir. Je reviendrai vers cette discussion quand j'aurai réussi à m'en sortir.

    Merci.

Discussions similaires

  1. [Excel] Validation de données
    Par ptitsoleil87 dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 21/12/2005, 19h35
  2. Problème de validation de données
    Par loutsky dans le forum Access
    Réponses: 3
    Dernier message: 23/11/2005, 14h11
  3. validation de donnée... et post
    Par sonialem2000 dans le forum Bases de données
    Réponses: 12
    Dernier message: 13/07/2004, 02h34
  4. dbgrid AND validation des données
    Par samlerouge dans le forum Bases de données
    Réponses: 10
    Dernier message: 11/06/2004, 23h08
  5. Validation de données à partir d'un XML Schema
    Par leup dans le forum Valider
    Réponses: 2
    Dernier message: 10/06/2004, 08h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo