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

Langage Java Discussion :

Généricité, ou presque..


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de ploxien
    Inscrit en
    Février 2006
    Messages
    467
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Février 2006
    Messages : 467
    Par défaut Généricité, ou presque..
    Hello,

    J'ai un petit souci... J'ai un programme qui fonctionne bien! Tant mieux... Mais il est vraiment pas joli!

    En gros, je fais un programme de configuration, qui prend des valeurs dans un XML (qui retourne des String) et qui doit les stocker dans une classe (grace au paquetage reflect)

    Mon souci est le suivant: Quand je stock mes valeurs, je dois faire un traitement différent pour chaque type possible, et il y en a une floppée:
    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
        Class[] classes = {    boolean.class, Boolean.class, 
                byte.class, Byte.class, 
                short.class, Short.class, 
                int.class, Integer.class, 
                long.class, Long.class,
                float.class, Float.class,
                double.class, Double.class,
                String.class,
                boolean[].class, Boolean[].class,
                byte[].class, Byte[].class,
                short[].class, Short[].class,
                int[].class, Integer[].class,
                long[].class, Long[].class,
                float[].class, Float[].class,
                double[].class, Double[].class,
                String[].class};
    Cela car je n'ai pas réussi (et pourtant j'ai essayé un bon moment) à envoyer un objet dans la méthode set de reflect... Attention à ne pas oublier les tableaux
    Sinon il me met une exception du genre (pour u boolean):
    java.lang.IllegalArgumentException: Can not set boolean field Configuration.Config01.booleanP to java.lang.String

    Voici donc mon programme (une partie), si quelqun a une idée, je suis vraiment preneur!!

    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
     
    c=this.o.getClass();
     f=c.getFields();
    ...
    public void endElement...    
     
        // Type of current field
        int intType = searchArray(classes, type);
        switch(intType){                    
            case BOOLEAN_PRIMITIVE: 
            case BOOLEAN: val = Boolean.parseBoolean(this.value.get(0)); break;
            case BYTE_PRIMITIVE:
            case BYTE: val = Byte.parseByte(this.value.get(0)); break;
            case SHORT_PRIMITIVE:
            case SHORT: val = Short.parseShort(this.value.get(0)); break;
            case INTEGER_PRIMITIVE: 
            case INTEGER: val = Integer.parseInt(this.value.get(0)); break;
            case LONG_PRIMITIVE: 
            case LONG: val = Long.parseLong(this.value.get(0)); break;
            case FLOAT_PRIMITIVE: 
            case FLOAT: val = Float.parseFloat(this.value.get(0)); break;
            case DOUBLE_PRIMITIVE: 
            case DOUBLE: val = Double.parseDouble(this.value.get(0)); break;
            case STRING: val = this.value.get(0); break;
            case BOOLEAN_P_ARRAY:
                boolean[] arrayBooleanP = new boolean[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayBooleanP[i]=Boolean.parseBoolean(this.value.get(i));
                val=arrayBooleanP;
                break;
            case BOOLEAN_ARRAY:
                Boolean[] arrayBoolean = new Boolean[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayBoolean[i]=Boolean.parseBoolean(this.value.get(i));
                val=arrayBoolean;
                break;
            case BYTE_P_ARRAY:
                byte[] arrayByteP = new byte[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayByteP[i]=Byte.parseByte(this.value.get(i));
                val=arrayByteP;
                break;
            case BYTE_ARRAY:
                Byte[] arrayByte = new Byte[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayByte[i]=Byte.parseByte(this.value.get(i));
                val=arrayByte;
                break;
            case SHORT_P_ARRAY:
                short[] arrayShortP = new short[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayShortP[i]=Short.parseShort(this.value.get(i));
                val=arrayShortP;
                break;
            case SHORT_ARRAY:
                Short[] arrayShort = new Short[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayShort[i]=Short.parseShort(this.value.get(i));
                val=arrayShort;
                break;
            case INTEGER_P_ARRAY:
                int[] arrayIntP = new int[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayIntP[i]=Integer.parseInt(this.value.get(i));
                val=arrayIntP;
                break;
            case INTEGER_ARRAY:
                Integer[] arrayInt = new Integer[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayInt[i]=Integer.parseInt(this.value.get(i));
                val=arrayInt;
                break;
            case LONG_P_ARRAY:
                long[] arrayLongP = new long[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayLongP[i]=Long.parseLong(this.value.get(i));
                val=arrayLongP;
                break;
            case LONG_ARRAY:
                Long[] arrayLong = new Long[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayLong[i]=Long.parseLong(this.value.get(i));
                val=arrayLong;
                break;
            case FLOAT_P_ARRAY:
                float[] arrayFloatP = new float[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayFloatP[i]=Float.parseFloat(this.value.get(i));
                val=arrayFloatP;
                break;
            case FLOAT_ARRAY:
                Float[] arrayFloat = new Float[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayFloat[i]=Float.parseFloat(this.value.get(i));
                val=arrayFloat;
                break;
            case DOUBLE_P_ARRAY:
                double[] arrayDoubleP = new double[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayDoubleP[i]=Double.parseDouble(this.value.get(i));
                val=arrayDoubleP;
                break;
            case DOUBLE_ARRAY:
                Double[] arrayDouble = new Double[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayDouble[i]=Double.parseDouble(this.value.get(i));
                val=arrayDouble;
                break;
            case STRING_ARRAY:
                String[] arrayString = new String[this.value.size()];
                for(int i=0;i<this.value.size();i++)
                    arrayString[i]=this.value.get(i);
                val=arrayString;
                break;
        }
     
         f[index].set(this.o, val);
     
    ...
    Ah, et BOOLEAN_PRIMITIVE, .... sont des constantes entières qui référencent le tableau dans le code en dessus... (des indices de tableaux)

    Et la, je voudrais ajouter une vérification sur le range de val... Donc je dois l'ajouter 50 millions de fois... Vraiment pénible...

    Help please

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    Citation Envoyé par ploxien
    Et la, je voudrais ajouter une vérification sur le range de val...
    Traduction ????


    Que veux-tu faire exactement ? Ce n'est pas clair du tout !
    Penses que nous ne sommes pas plongé dans ton code comme toi tu peux l'être !


    a++

  3. #3
    Membre éclairé Avatar de ploxien
    Inscrit en
    Février 2006
    Messages
    467
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Février 2006
    Messages : 467
    Par défaut
    Ouais, t'as raison, désolé...

    Mais le truc du range, c pas important...

    Ce que je veux, c'est vraiment simplifier ce code! Faire un traitement générique pour n'importe quel type! Si c'est possible...

    Merci

  4. #4
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par ploxien
    Ce que je veux, c'est vraiment simplifier ce code! Faire un traitement générique pour n'importe quel type! Si c'est possible...
    Mais que doit faire ce code ??
    Qu'est-ce qu'il reçoit en entrée ? A quoi correspondent les variables classes, type, this.value, etc...

    Comment pourrait-on simplifier un code sans savoir ce qu'il fait !?!

    a++

  5. #5
    Membre éclairé Avatar de ploxien
    Inscrit en
    Février 2006
    Messages
    467
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Février 2006
    Messages : 467
    Par défaut
    Je précise:
    Pour chaque type, je fait cela:

    - Je prend this.value.get(0), ce qui me donne la String qui provient du XML (p.ex, "true", "3.4", "abc"). Donc n'importe quel type est retourné en String...

    - Ensuite je transforme cette valeur dans le type de destination (ici Byte)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    val = Byte.parseByte(this.value.get(0));
    - Ensuite je fais un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    f[index].set(this.o, this.value.get(0));
    ce qui stock la valeur (prise précédement dans le XML) dans une variable d'une autre classe (java.lang.reflect). C'est ici que se situe le prob, l'objet que j'envoie doit être du bon type (ouais, forcément).

    Donc ce que je voudrais faire, c'est ça: j'ai un type dans une variable du genre de Class type=...; Je voudrais donc transformer un String dans ce type, qu'il soit n'importe quoi!

    C'est plus clair?? Encore des précisions??

    Merci

  6. #6
    Membre éclairé Avatar de ploxien
    Inscrit en
    Février 2006
    Messages
    467
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Février 2006
    Messages : 467
    Par défaut
    Donc remplacer tout ca par un truc du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    val=classes[intType].cast(this.value.get(0));
    (classes[intType] vaut int.class, Byte.class, Boolean.class, boolean.class, ...)
    Sauf que ca ca me donne un exception:java.lang.ClassCastException
    at java.lang.Class.cast(Unknown Source)


  7. #7
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par ploxien
    C'est plus clair??
    Je pense : tu veux convertir des données de type String vers le type de l'attribut de ta classe, pour ensuite pouvoir l'affecter sans ClassCastException...

    C'est normal que la méthode cast() ne fonctionne pas, car un cast se contente de changer le type de la référence de l'objet, mais pas le type lui même. Bref tu es obligé de convertir l'objet.

    Le plus simple pour éviter de faire de gros switch/case c'est de définir une interface pour les objets qui se chargeront de cette conversion, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public interface Parser<T> {
    	public T parse(String source);
    }

    L'idée étant d'utiliser une classe pour la conversion des données. Cette classe contiendra une Map affectant un Parser à un type Java. Le constructeur de cette classe pourrait définir un certain nombre de parser par défaut.
    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    class Converter {
     
    	private final Map<Class,Parser> parsers = new HashMap<Class, Parser>();
     
     
    	// Ajout d'un parser pour un type
    	public <T> void addParser(Class<T> type, Parser<T> parser) {
    		this.parsers.put(type, parser);
    	}
     
    	// Recher d'une parser selon le type
    	public <T> Parser<T> getParser(Class<T> type) {
    		return (Parser<T>) this.parsers.get(type);
    	}
     
     
    	public Converter() {
    		// Ajout de parser par défaut
    		// Par exemple pour Integer et int :
     
    		// Creation du parser :
    		Parser<Integer> intParser = new Parser<Integer>() {
    			public Integer parse(String source) {
    				return Integer.parseInt(source);
    			}
    		};
     
    		// Association avec les type Integer et int :
    		addParser(Integer.class, intParser);
    		addParser(int.class,     intParser);
     
    		// etc. pour les autres types	
    	}
     
    	...

    Ensuite il suffit de faire une méthode de conversion qui utilisera le bon parser selon le type :
    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    	public <T> T convert(Class<T> type, List<String> value)
    		throws Exception {
     
    		Object result = null;
     
    		if (type.isArray()) {
    			// Cas particulier pour les tableau
     
    			// 1. On récupère le parser pour le type de base du tableau :
    			Parser parser = getParser(type.getComponentType());
    			if (parser==null) {
    				throw new Exception("No parser for type " + type.getComponentType());
    			}
     
    			// 2. On crée le tableau via la reflection :
    			result = Array.newInstance(type, value.size());
    			Object[] array = (Object[]) result;
     
    			// 3. On affecte chaque élément du tableau après conversion :
    			int i=0;
    			for (String source : value) {
    				array[i] = parser.parse(source);
    				i++;
    			}
    		} else {
    			// Cas standard (affectation simple)
    			Parser parser = getParser(type);
    			if (parser==null) {
    				throw new Exception("No parser for type " + type);
    			}
    			result = parser.parse(value.get(0));
    		}
    		return ignoreTypeSafetyWarning(result); 
    	}
     
    	@SuppressWarnings("unchecked")
    	private <T> T ignoreTypeSafetyWarning(Object o) {
    		return (T) o; // warning type safety qui peut être ignoré
    	}

    Citation Envoyé par ploxien
    Encore des précisions??
    En fait tu nous as dit ce que tu voulais faire... mais on ignore encore pourquoi ! Bref s'il existe des solutions toutes faites on ne peut pas te les donner car on ignore le but exact de tout cela mis à part la conversion des types.

    Il ne faut pas hésiter à donner un max d'info pour améliorer la qualité des réponses que l'on obteindra


    a++

  8. #8
    Membre Expert
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Par défaut
    Il me semble avoir compris ton souci.
    L'idée, c'est qu'en entrée tu as une liste de String, et que tu désires utiliser cette liste pour setter la valeur d'un attribut dans une classe qui peut être à peu près de n'importe quel type (tableau ou non).

    Je n'ai pas vraiment d'idée plus "propre" que ce que tu as fait. Mais si j'étais à ta place, j'irais jeter un coup d'oeil au code Struts qui permet de populer un Form à partir d'une requête. Ils ont du avoir la même problématique (les attributs du Form peuvent être de type quelconque et les valeurs dans la requête sont sous la forme chaîne de caractères). Ils ont peut être eu une idée sympa

    Edit : il semblerait que tes précisions pendant que je répondais confirme ce que j'avais compris

  9. #9
    Membre éclairé Avatar de ploxien
    Inscrit en
    Février 2006
    Messages
    467
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Février 2006
    Messages : 467
    Par défaut
    Oui, c'est exactement ça!!

    Je vais regarder du coté de Struts...
    Merci pour l'info et certainement à bientôt

    ++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [architecture] pour de la généricité, vous feriez quoi ?
    Par Alec6 dans le forum Débats sur le développement - Le Best Of
    Réponses: 39
    Dernier message: 03/07/2006, 14h39
  2. Réponses: 3
    Dernier message: 23/08/2005, 11h02
  3. Réponses: 1
    Dernier message: 26/07/2005, 08h33
  4. [Ada 95] Généricité de type/package
    Par kindool dans le forum Ada
    Réponses: 5
    Dernier message: 19/05/2005, 11h54
  5. [jonas] presque presque... mais pas encore
    Par stailer dans le forum JOnAS
    Réponses: 6
    Dernier message: 26/05/2004, 10h59

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