-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 
Author Message
 Post subject: javax.persistence.MapKey broken in 3.2.0GA (?)
PostPosted: Tue Nov 07, 2006 9:38 am 
Newbie

Joined: Tue Jun 14, 2005 6:41 am
Posts: 10
Hi.

Is import javax.persistence.MapKey broken in 3.2.0GA, or am I missing something very fundamental?

I have googled for everything I can think of, search most docs and jira.

The class at the bottom using a Set in the OneToMany mapping works. Changing the Set to a Map, adding @Mapkey seems to break lazy loading. Using a Map and javax.persistence.MapKey, the @OneToMany mapping parcels isn't loaded when first accessed. Well, it is loaded, but if the first access is Map.put, it will just init the map, but ignore the put.

When using javax.persistence.MapKey I have to change this method from:

Code:
public void addParcel(Parcel parcel) {
      parcel.setProperty(this);
      this.parcels.put(parcel.getObjectId(), parcel); // this will just init this.parcels, the put will be ignored
   }


to:

Code:
public void addParcel(Parcel parcel) {
      parcel.setProperty(this);
      this.parcels.put(parcel.getObjectId(), parcel);   // this will trigger lazy load, but not add to collection...
                this.parcels.put(parcel.getObjectId(), parcel); // ...and this will add to collection.
   }


or

Code:
public void addParcel(Parcel parcel) {
                logger.debug(this.parcels); // This will trigger lazy load..
      parcel.setProperty(this);
      this.parcels.put(parcel.getObjectId(), parcel);   // .. and this will add to collection
   }



Code:
package se.lantmateriet.elips.poc.domain.model;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;

@Entity
public class Property extends AbstractDomainEntity {

   @OneToMany(mappedBy="property", cascade=CascadeType.ALL)
   //@MapKey(name="objectId")
   //private Map<UUID, Parcel> parcels;
   private Set<Parcel> parcels;
   
   public Property(UUID objectId, Integer objectVersion) {
      super(objectId, objectVersion);
      this.parcels = new HashSet<Parcel>();//new HashMap<UUID, Parcel>();
   }

   private Property() {
      super();
   }
      
   public void addParcel(Parcel parcel) {
      parcel.setProperty(this);
      this.parcels.add(parcel);
      //this.parcels.put(parcel.getObjectId(), parcel);
   }
   
   public void removeParcel(Parcel parcel) {
      this.parcels.remove(parcel);//(parcel.getObjectId());
   }
   
}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 07, 2006 8:15 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
you must do getParcels()..., not parcels.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 08, 2006 3:10 am 
Newbie

Joined: Tue Jun 14, 2005 6:41 am
Posts: 10
So there is a difference in how I have to access a Set and a Map in hibernate? The above example using a Set does work without a getter. Also I'm unable to find anything in JPA that says I need to go through a getter, is this hibernate specific?

Besides that, it still doesn't work even if I add a getter:

Code:
package se.lantmateriet.elips.poc.domain.model;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;

@Entity
public class Property extends AbstractDomainEntity {

   @OneToMany(mappedBy="property", cascade=CascadeType.ALL)
   @MapKey(name="objectId")
   private Map<UUID, Parcel> parcels;
   
   public Property(UUID objectId, Integer objectVersion) {
      super(objectId, objectVersion);
      this.parcels = new HashMap<UUID, Parcel>();
   }

   private Property() {
      super();
   }
      
   public void addParcel(Parcel parcel) {
      parcel.setProperty(this);
      this.getParcels().put(parcel.getObjectId(), parcel);
   }
   
   public void removeParcel(Parcel parcel) {
      this.getParcels().remove(parcel.getObjectId());
   }

   public Map<UUID, Parcel> getParcels() {
      return this.parcels;
   }
   
}


The line

this.getParcels().put(parcel.getObjectId(), parcel);

will trigger the load for this.parcels, but nothing is added into the map.

My unittest first didn't see this behaviour since i had some asserts that touched the content of this.parcels, and therefore triggered the load. But if I remove everything that touch it, the I'm missing one sql insert since nothing was put into the map, so hibernate thinks nothing changed...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 08, 2006 5:50 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Hum actually I am wrong.
The spec mandates the use of the getter (begining of the spec)
but Hibernate does not.

I really don't understand what is going on on your installation (esp if you don't bytecode enhance the classes). My unit tests works fine.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 08, 2006 6:45 pm 
Newbie

Joined: Tue Jun 14, 2005 6:41 am
Posts: 10
No bytecode enhance afaik. If I click on the instance in eclipse debug I get se.lantmateriet.elips.poc.domain.model.Property@461b6640. If it was enhanced I would see that there, right?

What unit tests are you refering to? You are sure that those tests don't touch the map after it's loaded and before the put? The only time I see this is if the collection mapped with javax.persistence.MapKey contains objects, and the entity containing the lazy collection is loaded from db, and the first access to the collection mapped with javax.persistence.MapKey is a put.

If I do something with the map first, then it's loaded just fine and the put works.

Thanks,

/Magnus


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 08, 2006 6:57 pm 
Newbie

Joined: Tue Jun 14, 2005 6:41 am
Posts: 10
emmanuel wrote:
Hum actually I am wrong.
The spec mandates the use of the getter (begining of the spec)
but Hibernate does not.


Really?

I just read "2.1.1 Persistent Fields and Properties" and I interpret it as that I don't have to use a getter if I use field based access and mapping. And I do.

/Magnus


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 13, 2006 1:09 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
I am referring to the Hibernate Annotations unit test suite included in the distribution.

If you can create a minimal working testcase showing the issue, add it to JIRA.

From 2.1
Quote:
The persistent state of an entity is represented by instance variables, which may correspond to Java-
Beans properties. An instance variable may be directly accessed only from within the methods of the
entity by the entity instance itself. Instance variables must not be accessed by clients of the entity. The
state of the entity is available to clients only through the entity’s accessor methods (getter/setter methods)
or other business methods. Instance variables must be private, protected, or package visibility.


2.1.1 is for the persistence provider.

But in your case, this seems to be compliant

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 14, 2006 4:53 am 
Newbie

Joined: Tue Jun 14, 2005 6:41 am
Posts: 10
emmanuel wrote:
I am referring to the Hibernate Annotations unit test suite included in the distribution.

If you can create a minimal working testcase showing the issue, add it to JIRA.


Done. http://opensource.atlassian.com/project ... se/ANN-491

emmanuel wrote:
From 2.1
Quote:
The persistent state of an entity is represented by instance variables, which may correspond to Java-
Beans properties. An instance variable may be directly accessed only from within the methods of the
entity by the entity instance itself. Instance variables must not be accessed by clients of the entity. The
state of the entity is available to clients only through the entity’s accessor methods (getter/setter methods)
or other business methods. Instance variables must be private, protected, or package visibility.


2.1.1 is for the persistence provider.

But in your case, this seems to be compliant


Sure, but it does say "An instance variable may be directly accessed only from within the methods of the entity by the entity instance itself.". So I don't need the getter. I can use the field from within my class. "methods of the entity" != "Java-Beans properties" afaik, or is that interpretation wrong?

Anyway, the unitttest breaks in both cases.

/Magnus


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.