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

Collection et Stream Java Discussion :

ResourceBundle.getString sans MissingResourceException


Sujet :

Collection et Stream Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 22
    Par défaut ResourceBundle.getString sans MissingResourceException
    Bonjour à tous,

    Je travaille actuellement sur une interface graphique qui utilise donc une instance de ResourceBundle pour l'internationalisation. Or comme vous le savez sûrement déjà, la méthode getString(String key) lance l'exception MissingResourceException lorsque la clé est introuvable. Jusque là, je n'avais aucun problème, parce que toutes les parties internationalisables étaient clairement définies, et identifiables par une clé.

    Jusqu'à maintenant.

    Une partie de l'application est générée en fonction de la configuration. Cette partie comprend un graphique qui se trouve dans un onglet d'un JTabbedPane. Il y a donc le nom de l'onglet, et la légende du graphe qui doivent être internationalisé. Chacune des clés des ressources est donc calculée et peut varier en fonction de la configuration. Il peut donc arriver que la configuration amène donc le programme à chercher des clés qui n'existent pas. Les contraintes sont les suivantes :
    • Aucune exception ne doit arriver dans l'EDT, cela empêche l'affichage de l'écran qui contient également des parties prédéfinies
    • Du fait de la structure du code, les recherches de texte internationalisé sont assez dispersées dans le code, et non facilement factorisable.
    • J'aimerai toucher le moins possible à l'existant, avec une solution propre, càd utiliser au maximum les API Java standard.


    Mon but premier est donc que l'instance du ResourceBundle renvoie la clé elle-même lorsque getString() est appelée si la ressource n'existe pas. En fait, pour être clair, je voudrais que la classe ResourceBundle se comporte comme le fameux gettext.

    L'héritage est impossible, les méthodes getObject et getString sont déclarées final.
    L'encapsulation est également écartée pour la même raison, et parce que je tiens à conserver l'utilisation de la classe ResourceBundle. Tout le code l'utilise actuellement.

    Pensez-vous qu'il y a une solution ? En avez-vous une ? Ou bien faudra-t-il que je me contente d'ouvrir une RFE sur le bugtracker de Sun ?

  2. #2
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    D'après tes contraintes, la seule solution que je vois est de créer un fichier de ressources de base (sans extensions) avec la totalité des mots clé, chacun ayant pour valeur le mot clé lui-même.
    Tu vas devoir faire une recherche dans tous le projet pour connaître la liste exhaustive des mots clés utilisés, tu n'as pas vraiment le choix.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 22
    Par défaut
    Ah ça par contre, ça va être assez difficile

    J'ai oublié de préciser clairement que les clés des parties dynamiques de l'interface sont générées en partie avec la configuration, qui peut changer.
    Adaptée à ma situation, ta solution reviendrait à générer un tableau contents pour en faire un ListResourceBundle, et le rajouter ou le déclarer comme bundle racine. Pas forcément évident, ni le plus élégant, mais cela permettrait de garder le ResourceBundle comme classe.

    Bon en gros, merci de m'avoir mis sur une piste

  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 hermes1983 Voir le message
    Ah ça par contre, ça va être assez difficile
    Pas forcément : tu n'est pas obligé d'utiliser un fichier *.properties

    Combien as-tu de fichier *.properties ? As-tu un fichier de base (sans notion de langue) ?

    a++

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 22
    Par défaut
    J'ai effectivement un fichier de base (message.properties) et un fichier par locale utilisée (message_fr_FR.properties par exemple, bien que ce ne soit pas le seul). Par contre, je n'ai actuellement qu'un seul fichier pour toutes les chaînes de l'application.

    Par contre, qu'est-ce que tu entends par "tu n'es pas obligé d'utiliser un properties" ? Une classe ou un ListResourceBundle ?

    Par ailleurs, la solution du bundle racine est également difficile. setParent est une méthode protected, et on ne peut pas rajouter de pairs clé-valeur à un ResourceBundle déjà instancié.

    Question annexe : Y a-t-il une raison pour qu'une classe soit aussi verrouillée ? La sécurité ?

  6. #6
    Membre Expert
    Avatar de professeur shadoko
    Homme Profil pro
    retraité nostalgique Java SE
    Inscrit en
    Juillet 2006
    Messages
    1 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 76
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : retraité nostalgique Java SE

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 257
    Par défaut
    Citation Envoyé par hermes1983 Voir le message
    J'ai effectivement un fichier de base (message.properties) et un fichier par locale utilisée (message_fr_FR.properties par exemple, bien que ce ne soit pas le seul). Par contre, je n'ai actuellement qu'un seul fichier pour toutes les chaînes de l'application.
    une première chose à changer: avoir une clef différente par "partie" de l'application (package + clef)

    Par ailleurs, la solution du bundle racine est également difficile. setParent est une méthode protected, et on ne peut pas rajouter de pairs clé-valeur à un ResourceBundle déjà instancié.
    j'ai pas essayé mais un hack qui me viendrait à l'esprit est d'utiliser ResourceBundle.Control pour avoir une partie des dictionnaires
    qui est redirigé dynamiquement vers une ressource en mémoire.
    (mais j'ai pas bien compris tes contraintes: je pensais qu'une méthode statique qui fait le tri et passe au resourceBundle OU à un code ad hoc suffirait)

  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 hermes1983 Voir le message
    J'ai effectivement un fichier de base (message.properties) et un fichier par locale utilisée (message_fr_FR.properties par exemple, bien que ce ne soit pas le seul).
    Hum donc il va falloir rusé un peu (je comptais utiliser le fichier de base ).


    Citation Envoyé par hermes1983 Voir le message
    Question annexe : Y a-t-il une raison pour qu'une classe soit aussi verrouillée ? La sécurité ?
    L'objectif est de simplifier la création des bundles. En clair tu n'a qu'à implémenter handleGetObject() qui consiste uniquement à récupérer une valeur selon sa clef. La méthode getString() s'occupant de tout le travail autour (appel du bundle parent si la clef est inexistante, etc...).


    Citation Envoyé par hermes1983 Voir le message
    Par contre, qu'est-ce que tu entends par "tu n'es pas obligé d'utiliser un properties" ? Une classe ou un ListResourceBundle ?
    Oui tu peux utiliser ta propose classe. En fait si tu places une classe étendant ResourceBundle avec le même nom de base que tes fichiers properties, elle sera utilisée de préférence.

    En clair dans ton cas si tu crée une classe nommé "message" dans le même package que tes fichiers *.properties, c'est cette dernière qui sera utilisé comme ResourceBundle.

    Par exemple avec une classe "message" (sans majuscule c'est important) :
    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
    public class message extends ResourceBundle {
    	@Override
    	public Enumeration<String> getKeys() {
    		// On retourne une enumeration vide :
    		return new Enumeration<String>() {
    			public boolean hasMoreElements() {
    				return false;
    			}
    			public String nextElement() {
    				throw new NoSuchElementException();
    			}
    		};
    	}
     
    	@Override
    	protected Object handleGetObject(String key) {
    		// On retourne directement la clef :
    		return key;
    	}
    }
    Tu renvois directement les clef comme valeur. Comme le bundle "message" est utilisé en dernier cela marche très bien ! Lorsque tu fais getBundle("message") avec la langue "fr_FR", tu vas donc charger dans l'ordre :
    • message_fr_FR.properties
    • message_fr.properties
    • message.class (en priorité sur message.properties)



    Le seul problème dans ton cas c'est qu'il va être pris en priorité et que ton fichier "message.properties" ne sera plus utilisé


    La solution serait de le charger par toi même, ce qui donnerait ceci :
    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
    public class message extends ResourceBundle {
     
    	private PropertyResourceBundle properties;
     
    	public message() throws IOException {
    		// On charge le fichier *.properties du même nom, s'il existe :
    		InputStream in = getClass().getResourceAsStream(getClass().getSimpleName()+".properties");
    		if (in!=null) {
    			try {
    				this.properties = new PropertyResourceBundle(in);
    			} finally {
    				in.close();
    			}
    		} else {
    			this.properties = null;
    		}
    	}
     
    	@Override
    	public Enumeration<String> getKeys() {
    		if (this.properties==null) {
    			// On retourne seulement les clefs du fichier properties :
    			return this.properties.getKeys();
    		}
    		// Sinon on retourne une enumeration vide :
    		return new Enumeration<String>() {
    			public boolean hasMoreElements() {
    				return false;
    			}
    			public String nextElement() {
    				throw new NoSuchElementException();
    			}
    		};
    	}
     
    	@Override
    	protected Object handleGetObject(String key) {
    		Object value = null;
    		if (this.properties!=null) {
    			value = this.properties.handleGetObject(key);
    		}
    		return value!=null ? value : key;
    	}
     
    }

    Et là tu devrais avoir le comportement souhaité (le bundle parent ne renvoi jamais 'null').

    a++

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

Discussions similaires

  1. MissingResourceException : ResourceBundle
    Par sylverspoon dans le forum Langage
    Réponses: 11
    Dernier message: 10/12/2009, 15h35
  2. [WSAD] ResourceBundle et MissingResourceException
    Par petitelulu dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 23/09/2004, 11h37
  3. MDI sans MFC, possible ?
    Par delire8 dans le forum MFC
    Réponses: 4
    Dernier message: 17/06/2002, 07h38
  4. [Kylix] Fiches sans bordure
    Par alex dans le forum EDI
    Réponses: 4
    Dernier message: 28/04/2002, 21h19

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