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

Hibernate Java Discussion :

Propriétés de proxy toujours null ! (avec session.load ou en lazy fetch)


Sujet :

Hibernate Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Avril 2007
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 14
    Par défaut Propriétés de proxy toujours null ! (avec session.load ou en lazy fetch)
    Bonjour,

    Je travaille sur un SI de pharmacochimie sur des substances naturels qui se base sur les technos Spring/Maven/Hibernate/Wicket. Cependant avec hibernate, j'ai souvent des problèmes de chargement de valeur pour les proxy hibernate.

    En général, je charge mes objets avec des "get" (via le HibernateTemplate fourni par Spring), et afin de minimiser les chargements d'objets j'ai des associations en mode "fetch = FetchType.LAZY". Ces objets sont donc chargés en tant que proxy et quand on accède à ses propriétés, parfois toutes les propriétés de l'objet restent à "null" (même la propriété annotée @Id !). Aucune requête SQL n'est donc exécutée par Hibernate pour aller chercher leur valeurs.

    Après de moultes tests et de longues recherches sur ce phénomène inexpliqué, j'ai mis en place un simple exemple qui m'a fait me rendre compte que le même phénomène se passait quand je chargais mes objets avec un "load". Toutes les propriétés restent à "null". Voici le code de l'exemple, on ne peut pas faire plus simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Session session = (Session) sf.openSession();
     
    Purification p1 = (Purification) session.load(Purification.class, 18);
    LOG.debug("purification p1, id : '" + p1.idPurification + "', reference : '" + p1.ref + "';");
    LOG.debug("classe : " + p1.getClass().getSimpleName() + ", estProxy : " + (p1 instanceof HibernateProxy));
     
    Purification p2 = (Purification) session.load(Purification.class, 4445);
    LOG.debug("purification p2, id : '" + p2.idPurification + "', reference : '" + p2.ref + "';");
    LOG.debug("classe : " + p2.getClass().getSimpleName() + ", estProxy : " + (p2 instanceof HibernateProxy));
     
    session.close();
    Et voici le résultat de son exécution :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    [avec "load" (pas de logs SQL !)]
    11:57:09.398 DEBUG (SandboxPage.java:<init>:33) purification p1, id : 'null', reference : 'null';
    11:57:09.401 DEBUG (SandboxPage.java:<init>:34) classe : Purification_$$_javassist_21, estProxy : true
    11:57:09.402 DEBUG (SandboxPage.java:<init>:37) purification p2, id : 'null', reference : 'null';
    11:57:09.403 DEBUG (SandboxPage.java:<init>:38) classe : Purification_$$_javassist_21, estProxy : true
    14:58:53.215  INFO (org.apache.wicket.protocol.http.RequestLogger) time=119,event=BookmarkablePage[nc.ird.cantharella.web.pages.SandboxPage()],response=BookmarkablePage[nc.ird.cantharella.web.pages.SandboxPage()],sessionid=67FA7E14AEF7A95984A46E8D06A409B9,sessionsize=2284,sessionstart=Fri Apr 30 14:58:53 NCT 2010,requests=2,totaltime=119,activerequests=0,maxmem=66M,total=40M,used=24M
    On voit bien que l'objet est chargé en tant que proxy avec javassist, ainsi que les valeurs du proxy rester à "null".
    Un autre phénomène bizarre est que lorsque je charge un objet qui n'existe pas (l'id 17 existe dans la base mais pas l'id 4455 !), le comportement est exactement le même. Bien que dans les docs, il soit spécifié qu'une exception devrait être lancer. La javadoc d'HibernateTemplate de Spring" précise notamment :

    public void load(Object entity,
    Serializable id)
    throws DataAccessException

    Description copied from interface: HibernateOperations
    Load the persistent instance with the given identifier into the given object, throwing an exception if not found.
    Le même exemple, avec des "get" au lieu des "load" donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [avec get]
    ... LOGS SQL...
    12:00:21.233 DEBUG (SandboxPage.java:<init>:33) purification p1, id : '18', reference : 'RRR';
    12:00:21.236 DEBUG (SandboxPage.java:<init>:34) classe : Purification, estProxy : false
    ... LOGS SQL ...
    12:00:21.243 ERROR (org.apache.wicket.RequestCycle) Can't instantiate page using constructor public nc.ird.cantharella.web.pages.SandboxPage()
    org.apache.wicket.WicketRuntimeException: Can't instantiate page using constructor public nc.ird.cantharella.web.pages.SandboxPage()
    ...
    Caused by: java.lang.NullPointerException
    	at nc.ird.cantharella.web.pages.SandboxPage.<init>(SandboxPage.java:37)
    Tout est alors normal : le premier objet est là, bien chargé, et le second n'est effectivement pas trouvé.


    Voici pour info, le code de ma classe "Purification". On pourra noter que pour que des fonctions comme getLotSource fonctionne, je suis obligé d'appeler sur certains objets la méthode "HibernateTools.initProxy" afin de remplacer le proxy par l'objet initialisé (j'y fais un "...getHibernateLazyInitializer().getImplementation()").


    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
    120
    121
    122
    123
    124
    125
    @Entity
    public class Purification extends AbstractModel implements Comparable<Purification> {
     
    	/** Logger */
    	// private static final Log LOG = LogTools.getLog();
    	/** Id de la purification */
    	@Id
    	@GeneratedValue
    	public Integer idPurification;
     
    	/** Référence de la manip */
    	@Length(max = LENGTH_MEDIUM_TEXT)
    	@Column(unique = true)
    	@NotEmpty
    	public String ref;
     
    	/** Manipulateur */
    	@NotNull
    	@ManyToOne(fetch = FetchType.EAGER, optional = false)
    	public Personne manipulateur;
     
    	/** Date de la manip */
    	@NotNull
    	@Temporal(TemporalType.DATE)
    	public Date date;
     
    	/** Méthode pour la purification **/
    	@NotNull
    	@ManyToOne(fetch = FetchType.EAGER, optional = false)
    	public MethodePurification methode;
     
    	// TODO passer en LAZY, sans provoquer de LAZY exception à la mise à jour d'une puri existante
    	/** Paramètres qui caractérisent la méthode pour cette purification */
    	@NotNull
    	@OneToMany(mappedBy = "id.pk1", fetch = FetchType.EAGER)
    	@Cascade( { CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN })
    	@OrderBy
    	@Fetch(value = FetchMode.SUBSELECT)
    	public List<ParamMethoPuriEffectif> paramsMetho;
     
    	/** Produit utilisé pour la purification **/
    	@NotNull
    	@ManyToOne(fetch = FetchType.EAGER, optional = false)
    	public Produit produit;
     
    	/** Masse avant l'extraction **/
    	@NotNull
    	@Min(value = 0)
    	public Float masseDepart;
     
    	/** Commentaire pour la manip */
    	@Lob
    	public String complement;
     
    	/** Détermine si la manip doit être confidentielle */
    	boolean confidentiel;
     
    	/** Date jusqu'à laquelle la purification est confidentielle */
    	@Future
    	@Temporal(TemporalType.DATE)
    	public Date dateConfidentialite;
     
    	/** Créateur */
    	@NotNull
    	@ManyToOne(fetch = FetchType.LAZY, optional = false)
    	public Personne createur;
     
    	/** Fractions produites par la purification */
    	@NotNull
    	@OneToMany(mappedBy = "purification", fetch = FetchType.LAZY)
    	@Cascade( { CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN })
    	@OrderBy
    	public List<Fraction> fractions;
     
    	/**
             * Constructeur
             */
    	public Purification() {
    		fractions = new ArrayList<Fraction>();
    		paramsMetho = new ArrayList<ParamMethoPuriEffectif>();
    	}
     
    	/**
             * Remonte au lot dont provient la purification
             * @return Le lot
             */
    	public Lot getLotSource() {
    		Produit curProd = produit;
    		while (curProd.isFraction()) {
    			// LOG.debug(curProd + " : " + produit.getClass().getSimpleName());
    			Fraction curFraction = (Fraction) curProd;
    			// LOG.debug("curFraction : " + curFraction);
    			// LOG.debug("curFraction.purification : " + curFraction.purification);
    			// LOG.debug("curFraction.purification.produit : " + curFraction.purification.produit);
    			curProd = curFraction.purification.produit;
    		}
    		AssertTools.assertClassOrInterface(curProd, Extrait.class);
     
    		Extrait extrait = (Extrait) curProd;
     
    		// LOG.debug("sans proxy : " + extrait.extraction);
    		// TODO comprendre pourquoi on doit explicitement charger le proxy pour récupérer les valeurs, valeurs null
    		// sinon
    		Extraction extraction = HibernateTools.initProxy(extrait.extraction, Extraction.class);
    		// LOG.debug("avec proxy : " + extraction);
    		// LOG.debug("extrait.extraction :" + extrait.extraction);
     
    		AssertTools.assertNotNull(extraction);
    		AssertTools.assertNotNull(extraction.lot);
    		return extraction.lot;
    	}
     
    	/** {@inheritDoc} */
    	@Override
    	public final String toString() {
    		return ref;
    	}
     
    	/** {@inheritDoc} */
    	@Override
    	public final int compareTo(Purification purification) {
    		return toString().compareTo(purification == null ? null : purification.toString());
    	}
     
    }
    J'utilise actuellement la version 3.5.1-Final d'Hibernate mais j'ai également essayé avec la 3.3.2.GA. J'ai testé aussi de charger Hibernate avec la librairie cglib au lieu de javaassist (changement du "bytecode.provider") mais rien n'y fait !

    Merci d'avance à ceux qui pourront me faire avancer dans cette recherche... et désolé pour la longueur du post.

  2. #2
    Membre averti
    Inscrit en
    Avril 2007
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 14
    Par défaut réponse

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

Discussions similaires

  1. [Core] Problème avec SessionFactory toujours à null
    Par vinou94400 dans le forum Hibernate
    Réponses: 1
    Dernier message: 20/09/2011, 11h03
  2. Réponses: 12
    Dernier message: 12/08/2010, 15h20
  3. Probleme Seam injection avec @In toujours nulle
    Par TomTomGo dans le forum Seam
    Réponses: 4
    Dernier message: 08/04/2009, 09h18
  4. Réponses: 8
    Dernier message: 11/08/2005, 09h32
  5. liste déroulante avec session
    Par leeloo076 dans le forum ASP
    Réponses: 3
    Dernier message: 19/03/2004, 11h01

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