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

Format d'échange (XML, JSON...) Java Discussion :

Unmarshaller un singleton [JAXB]


Sujet :

Format d'échange (XML, JSON...) Java

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 96
    Par défaut Unmarshaller un singleton
    Bonjour,

    Voici mon problème : j'ai un fichier XML qui contient différentes données de configuration. Je souhaite gérer (lire/écrire) ce fichier simplement. Pour cela il me semble que JAXB est adapté.
    Dans mon application j'ai donc un objet (Param) qui reprend les différentes données de configuration sous forme d'attributs.
    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
     
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
     
     
    @XmlRootElement(name = "param")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Param {
    	private static Param instance;
     
    	@XmlElement
    	private String data;
     
    	private Param(){
     
    	}
     
    	public static synchronized Param getInstance() {
    		if (null == Param.instance) {
    			Param.instance = new Param();
    		}
     
    		return Param.instance;
    	}
     
    	public String getData() {
    		return this.data;
    	}
    }
    Je veux que cet objet soit un singleton car les paramétres de l'appli sont communs à toute l'appli et je veux y avoir accès depuis n'importe où sans avoir à me trainer un lien vers cet objet.

    J'arrive à faire le unmarshal de mon fichier XML mais si je fais un getInstance() de celui-ci un nouvel objet est créé.
    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
     
    import java.io.File;
     
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.JAXBException;
    import javax.xml.bind.Unmarshaller;
     
    public class TestJaxb {
    	public static void main(String args[]) {
    		// Read xml config file. 
    		JAXBContext jaxbContext;
    		try {
    			jaxbContext = JAXBContext.newInstance(Param.class);
    			Unmarshaller um = jaxbContext.createUnmarshaller();
    			File _configFile = new File("param.xml");
    			Param param = (Param)um.unmarshal(_configFile);
    			System.out.println("Param 1 : " + param + "(" + param.getData() + ")");
    			param = Param.getInstance();
    			System.out.println("Param 2 : " + param + "(" + param.getData() + ")");
    		} catch (JAXBException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    }
    Effectivement, lors du unmarshal l'attribut instance prend la valeur par défaut (null). Du coup le getInstance() créé un nouvel objet.

    Ma question est donc : comment faire pour que lors du unmarshal mon attribut instance soit mis à jour.

    Merci pour vos suggestions.


    S. Combes

  2. #2
    Rédacteur
    Avatar de bulbo
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2004
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2004
    Messages : 1 259
    Par défaut
    Bonjour,

    Déjà ce que tu veux faire rappelle furieusement de l'inversion of control, je serais toi je jetterais un oeil à Spring Ioc au hasard c'est bien plus puissant et flexible pour répondre à ce genre de problématique qu'un coup de Jaxb .. bon c'est sur que ça ramène un brin de dépendances à ton projet pour le coup.


    Ensuite, attention, ton singleton n'est pas Thread-safe, c'est un moindre mal si tu le crées grâce à Jaxb en tout premier lieu.. mais bon il faut le savoir pour ne pas avoir de mauvaises surprises plus tard.

    Personnellement j'appliquerais cette modification à mon code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    	private Param(){
    		if (null == Param.instance) {
    			Param.instance = this;
    		}
    	}
     
    	public static synchronized Param getInstance() {
    		if (null == Param.instance) {
    			new Param();
    		}
     
    		return Param.instance;
    	}
    On n'est toujours pas thread-safe donc ce n'est pas vraiment pire que ce que tu avais avant

    Bulbo
    [Java] [NetBeans] [CVS]
    La FAQ Java
    Merci de ne pas me poser de questions techniques par MP.

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 96
    Par défaut
    Bonjour,

    Merci, cela fonctionne.
    Mais il y a un truc qui m'échappe. Comment fait JAXB pour exécuter un constructeur private


    S. Combes

  4. #4
    Rédacteur
    Avatar de bulbo
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2004
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2004
    Messages : 1 259
    Par défaut
    La construction se fait par reflection .. et je sais qu'il y a un truc (qui m'échappe là tout de suite) pour permettre d'accéder à ce qui est private.

    C'est sûrement ce que fait Jaxb.

    Bulbo
    [Java] [NetBeans] [CVS]
    La FAQ Java
    Merci de ne pas me poser de questions techniques par MP.

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 96
    Par défaut
    Merci, je viens de tester avec le code suivant
    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
     
    import java.lang.reflect.InvocationTargetException;
     
    import javax.xml.bind.JAXBException;
     
     
    public class TestJaxb {
    	public static void main(String args[]) throws SecurityException,
    			NoSuchMethodException, InstantiationException,
    			IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    		Param param;
    		try {
    			param = Param.getInstance();
    			System.out.println("Param 1 : " + param + "(" + param.getData() + ")");
    		} catch (JAXBException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
     
    		try {
    			param = Param.getInstance();
    			System.out.println("Param 2 : " + param + "(" + param.getData() + ")");
    		} catch (JAXBException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
     
    		// Introspection
    		// afficher toutes les méthodes de p
    		Class p = Param.class;
    		for (java.lang.reflect.Method m : p.getDeclaredMethods()) {
    			System.out.println("Méthode :  " + m);
    		}
    		// afficher tous les constructeurs de p
    		for (java.lang.reflect.Constructor c : p.getDeclaredConstructors()) {
    			System.out.println("Constructeur :  " + c);
    		}
    		java.lang.reflect.Constructor c = p.getDeclaredConstructor(null);
    		System.out.println("Constructeur par défaut :  " + c);
    		// Créer un objet avec le constructeur private
    		c.setAccessible(true);
    		Object o = c.newInstance(); // Attention : perte du type !
    		System.out.println("Objet :  " + o);
    		Param p2 = (Param) o;
    		System.out.println("Data :  " + p2.getData());
    	}
    }
    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
     
    import java.io.File;
     
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.JAXBException;
    import javax.xml.bind.Unmarshaller;
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
     
    @XmlRootElement(name = "param")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Param {
    	private static Param instance;
     
    	@XmlElement
    	private String data;
     
    	private Param() {
    		System.out.println("Exec constructeur de param : " + this.data);
    		if (null == Param.instance) {
    			Param.instance = this;
    		}
    	}
     
    	public static synchronized Param getInstance() throws JAXBException {
    		if (null == Param.instance) {
    			JAXBContext jaxbContext = JAXBContext.newInstance(Param.class);
    			Unmarshaller um = jaxbContext.createUnmarshaller();
    			File _configFile = new File("param.xml");
    			System.out.println("Avant unmarshal.");
    			Param.instance = (Param) um.unmarshal(_configFile);
    			System.out.println("Après unmarshal.");
    			System.out.println("static Param : " + Param.instance + "("
    					+ Param.instance.getData() + ")");
    		}
     
    		return Param.instance;
    	}
     
    	public String getData() {
    		return this.data;
    	}
    }
    et en sortie j'obtiens
    Avant unmarshal.
    Exec constructeur de param : null
    Après unmarshal.
    static Param : Param@e5b723(Toto)
    Param 1 : Param@e5b723(Toto)
    Param 2 : Param@e5b723(Toto)
    Méthode : public static synchronized Param Param.getInstance() throws javax.xml.bind.JAXBException
    Méthode : public java.lang.String Param.getData()
    Constructeur : private Param()
    Constructeur par défaut : private Param()
    Exec constructeur de param : null
    Objet : Param@15a8767
    Data : null
    Donc j'ai bien créé un nouvel objet Param avec l'introspection alors que le constructeur de Param est private.

    J'en arrive à la conclusion que le pattern Singleton peut être contourné.



    Question bonus : J'ai modifié ma classe Param afin que l'appel à JAXB soit fait par la méthode getInstance().
    A votre avis c'est une bonne idée ou pas ?


    S. Combes

  6. #6
    Rédacteur
    Avatar de bulbo
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2004
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2004
    Messages : 1 259
    Par défaut
    Vu que ce singleton n'est pas thread safe je n'aurais pas fait ainsi.

    Là en cas de deux (premiers) appels en parallèle de getInstance, l'instance sera null pendant toute l'init avec JAXB.. ce qui augmente la vulnérabilité de ce singleton à l'utilisation en multi-thread de manière conséquente.

    Moi j'aurais, au tout début de mon application, avant de démarrer quoi que ce soit d'autre, un code qui assurerait l'initialisation de mon singleton via JAXB.

    Ainsi je m'assure que l'instance crée est unique et je n'ai plus à me poser la question thread-safe or not thread-safe pour le reste des appels sur ce singleton.

    Bulbo
    [Java] [NetBeans] [CVS]
    La FAQ Java
    Merci de ne pas me poser de questions techniques par MP.

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 96
    Par défaut
    Merci pour toutes ces explications

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

Discussions similaires

  1. [Servlet]Singleton & cache
    Par lucimast dans le forum Servlets/JSP
    Réponses: 4
    Dernier message: 15/12/2004, 16h36
  2. Singleton héritable ?
    Par rolkA dans le forum C++
    Réponses: 10
    Dernier message: 11/12/2004, 16h22
  3. [Débutant] pattern singleton
    Par SirDarken dans le forum Débuter avec Java
    Réponses: 22
    Dernier message: 11/12/2004, 01h55
  4. Mutiple row in singleton select ????? [Important, merci]
    Par SkyDev dans le forum Bases de données
    Réponses: 6
    Dernier message: 20/04/2004, 14h02
  5. [debutant]Singleton
    Par bafman dans le forum Langage SQL
    Réponses: 6
    Dernier message: 13/01/2004, 15h41

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