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

Spring Java Discussion :

Créer un parseur personnalisé avec un bean interne


Sujet :

Spring Java

  1. #1
    Expert éminent sénior
    Avatar de Baptiste Wicht
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    7 431
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Suisse

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

    Informations forums :
    Inscription : Octobre 2005
    Messages : 7 431
    Points : 21 324
    Points
    21 324
    Par défaut Créer un parseur personnalisé avec un bean interne
    Bonsoir,

    J'utilise un namespace custom qui me permet de créer facilement un proxy pour un bean. Par exemple, ce proxy :

    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    <jtheque:proxy id="mainView" type="org.jtheque.core.managers.view.impl.frame.MainView"/>

    fait référence à ce bean :

    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    <bean id="_mainView" class="org.jtheque.core.managers.view.impl.frame.MainView" factory-method="get"/>

    Actuellement, je déduis simplement le nom du bean destination en ajoutant un "_" devant le nom du bean proxy.

    Voici mon parser :

    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
    public final class ProxyBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {
        @Override
        protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
            String id = element.getAttribute("id");
     
            builder.addConstructorArgValue('_' + id);
     
            builder.getBeanDefinition().setPrimary(true);
     
            try {
                builder.addConstructorArgValue(Class.forName(element.getAttribute("type")));
            } catch (ClassNotFoundException e) {
                parserContext.getReaderContext().error("Class not found", element, e);
            }
        }
     
        @Override
        protected Class<?> getBeanClass(Element element) {
            return LazyFactoryBean.class;
        }
    }
    et mon factory bean :

    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
    public final class LazyFactoryBean extends AbstractFactoryBean {
        private final String beanName;
        private final boolean swing;
        private final Class<?> beanClass;
     
        public LazyFactoryBean(String beanName, boolean swing, Class<?> beanClass) {
            super();
     
            this.beanName = beanName;
            this.swing = swing;
            this.beanClass = beanClass;
        }
     
        @Override
        public Class<?> getObjectType() {
            return beanClass;
        }
     
        @Override
        protected Object createInstance() {
            return Proxy.newProxyInstance(
                    ClassLoader.getSystemClassLoader(),
                    beanClass.getInterfaces(),
                    new LazyProxyHandler(beanName, swing));
        }
    }
    Tout cela marche très bien, mais avec ça, on peut toujours récupérer directement le bean de destination via son nom ou son type, ce que j'aimerais éviter...

    Alors déja première question : Est-ce que c'est possible de rendre invisible un bean à part en interne dans le parser ?

    Sinon, j'aimerais effectuer un refactoring pour pouvoir parser un bean à peu près comme ça :

    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    <bean id="_mainView" class="org.jtheque.core.managers.view.impl.frame.MainView" factory-method="get">
    <bean class="org.jtheque.core.managers.view.impl.frame.MainView" factory-method="get"/>
    </jtheque:proxy>

    mais je ne peux pas le déclarer directement en argument du constructeur de mon LazyFactoryBean car alors il serait alors résolu directement lorsque le proxy serait créé alors que je ne veux une instanciation du bean enfant qu'à l'utilisation.

    Donc, il me faut un moyen de déclarer un bean de manière interne à un autre mais sans créer ce bean interne à la création du bean externe.

    C'est assez tiré par les cheveux, je sais, mais j'aimerais bien qu'on ne puisse par récupérer le bean non proxy.

    Si quelqu'un a une idée, je lui serais très reconnaissant

    Egalement si quelqu'un voit une autre façon de faire qui convienne à mon objectif

    Le but étant de créer un proxy d'un bean qui ne va s'instancier que lors d'un appel de méthode sur lui et non pas lors de l'affectation du bean.

    Merci d'avance

    Baptiste

  2. #2
    Rédacteur
    Avatar de Hikage
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 177
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 177
    Points : 6 301
    Points
    6 301
    Par défaut
    Hello,

    Alors je vais essayer de répondre.

    Concernant la visibilité, le seul moyen que je connaisse pour éviter de pouvoir récupérer un bean via son nom est de passer par un bean interne (inner bean).

    Une autre solution possible cependant, du fait que tu parle d'un namespace serait d'avoir pour chaque proxy, un applicationContext fils du contexte générale (celui qui contient ton namespace).

    Dans ce contexte fils, tu n'aurais que ton bean
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <bean id="_mainView" class="org.jtheque.core.managers.view.impl.frame.MainView" factory-method="get"/>
    Ton proxy ressemblerait a ceci (le code n'est pas utilisable, c'est pour expliquer mon idé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
    17
    18
    19
    20
    21
    22
    23
     
    class Proxy{
     
    private Object target = null;
     
    public Proxy(ApplicationContext fils){
       this.childContext = fils;
    }
     
    public Object invoke(Method m, Object ... params){
        m.invoke(getTarget(), params);
    }
     
     
    // Intialisation à l'utilisation de la cible;
    public Object getTarget(){
     
     if(this.target == null) {
        this.target = childContext.getBeans("tonBean");
      }
      return this.target;
     
    }

    Le gain est double :

    • Le bean est complétement caché pour le contexte parent, impossible de le récupérer
    • Si le bean dans le contexte Fils est noté Lazy, il ne sera chargé qu'a son utilisation
    Hikage
    SCJP / SCWCD & SCWSJD Certified / Spring Framework Certified
    [Personal Web] [CV]

    F.A.Q Spring Framework - Participez !

  3. #3
    Expert éminent sénior
    Avatar de Baptiste Wicht
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    7 431
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Suisse

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

    Informations forums :
    Inscription : Octobre 2005
    Messages : 7 431
    Points : 21 324
    Points
    21 324
    Par défaut
    Salut,

    Je ne suis pas sûr d'avoir bien compris ta solution.

    Tu veux dire qu'il faudrait faire un deuxième applicationContext qui est enfant du root ?

    Mais après est-ce qu'une recherche dans le root ne cherche pas automatiquement dans les contextes enfants ?

  4. #4
    Rédacteur
    Avatar de Hikage
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 177
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 177
    Points : 6 301
    Points
    6 301
    Par défaut
    Citation Envoyé par Baptiste Wicht Voir le message
    Salut,

    Je ne suis pas sûr d'avoir bien compris ta solution.

    Tu veux dire qu'il faudrait faire un deuxième applicationContext qui est enfant du root ?

    Mais après est-ce qu'une recherche dans le root ne cherche pas automatiquement dans les contextes enfants ?
    Effectivement, pour chaque proxy, un applicationContext enfant serait créé ( tu le créerais toi même dans ton BeanDefinitionParser) avec comme père le contexte root.
    Tu fournirais ce context à ton proxy, qui l'utiliserai pour récupérer le bean cible quand cela est nécessaire (à l'utilisation et plus à l'instanciation).

    Pour répondre à ta question, Spring ne va pas chercher dans les fils.
    C'est le contraire en fait, dans le contexte Fils, si tu essaie de récupérer un bean et qu'il ne le trouve pas, il va chercher dans son contexte père.
    Hikage
    SCJP / SCWCD & SCWSJD Certified / Spring Framework Certified
    [Personal Web] [CV]

    F.A.Q Spring Framework - Participez !

  5. #5
    Expert éminent sénior
    Avatar de Baptiste Wicht
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    7 431
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Suisse

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

    Informations forums :
    Inscription : Octobre 2005
    Messages : 7 431
    Points : 21 324
    Points
    21 324
    Par défaut
    Citation Envoyé par Hikage Voir le message
    Effectivement, pour chaque proxy, un applicationContext enfant serait créé ( tu le créerais toi même dans ton BeanDefinitionParser) avec comme père le contexte root.
    Tu fournirais ce context à ton proxy, qui l'utiliserai pour récupérer le bean cible quand cela est nécessaire (à l'utilisation et plus à l'instanciation).

    Pour répondre à ta question, Spring ne va pas chercher dans les fils.
    C'est le contraire en fait, dans le contexte Fils, si tu essaie de récupérer un bean et qu'il ne le trouve pas, il va chercher dans son contexte père.
    Ah ok, je comprends mieux

    Par contre, comment est-ce que je peux dans mon parser créer un contexte qui contient justement le bean interne ?

  6. #6
    Rédacteur
    Avatar de Hikage
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 177
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 177
    Points : 6 301
    Points
    6 301
    Par défaut
    Dans ton parseur, tu accède au informations via DOM.
    De la, tu peux faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // Tu laisses Spring lire la configuration de la définition
    BeanDefinitionHolder definition = parserContext.getDelegate().parseBeanDefinitionElement(element);
     
    // Tu crée une applicationContext fils, utilisant le context root comme parent
    GenericApplicationContext appContext = new GenericApplicationContext(parentContext );
     
    // Tu enregistre la définition du bean fils
    appContext.registerBeanDefinition("_nomDuBean", definition.getBeanDefinition());
    Hikage
    SCJP / SCWCD & SCWSJD Certified / Spring Framework Certified
    [Personal Web] [CV]

    F.A.Q Spring Framework - Participez !

  7. #7
    Expert éminent sénior
    Avatar de Baptiste Wicht
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    7 431
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Suisse

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

    Informations forums :
    Inscription : Octobre 2005
    Messages : 7 431
    Points : 21 324
    Points
    21 324
    Par défaut
    Super

    J'ai bien avancé, juste encore 2 problèmes :
    • Dans le BeanParser, il y a moyen de récupérer le contexte en cours de création pour le mettre comme parent du contexte ? Pour le moment, je configure le parent du contexte une fois que j'ai besoin de créer mon bean, mais c'est pas très propre
    • Quand on crée un GenericApplicationContext, il y a moyen qu'il gère les annotations ? J'ai essayé de lui ajouter un bean CommonAnnotationBeanPostProcessor, mais ça n'a pas marché, les annotations ne sont pas prises en compte.


    Merci

  8. #8
    Rédacteur
    Avatar de Hikage
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 177
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 177
    Points : 6 301
    Points
    6 301
    Par défaut
    Pour l'applicationContext, à vérifier mais :

    ParserContext.getRegistry() te renvoi un BeanDefinitionRegistry que tu devrais pouvoir caster en ApplicationContext.

    Sinon pour le CommonAnnotationBeanPostProcessor, essaie de faire un context.refresh() après sa configuration.
    Hikage
    SCJP / SCWCD & SCWSJD Certified / Spring Framework Certified
    [Personal Web] [CV]

    F.A.Q Spring Framework - Participez !

  9. #9
    Expert éminent sénior
    Avatar de Baptiste Wicht
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    7 431
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Suisse

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

    Informations forums :
    Inscription : Octobre 2005
    Messages : 7 431
    Points : 21 324
    Points
    21 324
    Par défaut
    Pour les annotations, j'ai trouvé. Par contre, je viens d'essayer ta technique pour le contexte courant, mais ce n'est pas castable en ApplicationContext.

Discussions similaires

  1. Réponses: 10
    Dernier message: 24/07/2020, 16h53
  2. Réponses: 9
    Dernier message: 01/12/2010, 10h17
  3. Créer ma listbox personnalisé avec un Tpanel ? TScrollBox ?
    Par Coussati dans le forum Composants VCL
    Réponses: 14
    Dernier message: 04/01/2009, 20h17
  4. Comment créer un menu personnalisé avec Access2007
    Par marionAccess dans le forum Access
    Réponses: 6
    Dernier message: 24/01/2007, 16h29

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