To demo, I created 3 entities: MapHolderEntity, MapKeyEntity, and MapValueEntity. MapKeyEntity has no associations. MapHolderEntity holds a @OneToMany map of MapKeyEntities to MapValueEntities, where MapValueEntity has a @ManyToOne back to both MapKeyEntity and MapHolderEntity. Here are snippets of the entities:
Code:
@Entity
public class MapHolderEntity
{
// ...
@Id
@GeneratedValue( strategy = GenerationType.AUTO )
public Long getId() { return id; }
public String getName() { return name; }
@OneToMany( mappedBy = "holder", cascade = CascadeType.ALL )
@MapKey( name = "mapKey" )
public Map<MapKeyEntity, MapValueEntity> getMap() { return map; }
// ...
}
@Entity
public class MapKeyEntity
{
// ...
@Id
@GeneratedValue( strategy = GenerationType.AUTO )
public Long getId() { return id; }
public String getName() { return name; }
// ...
}
@Entity
public class MapValueEntity
{
// ...
@Id
@GeneratedValue( strategy = GenerationType.AUTO )
public Long getId() { return id; }
public String getName() { return name; }
@ManyToOne
public MapKeyEntity getMapKey() { return mapKey; }
@ManyToOne
public MapHolderEntity getHolder() { return holder; }
// ...
}
Now, if I populate them with some values and then do the following test:
Code:
public class MapStuffBugDemo extends ...
{
// ...
private GenericDao<MapHolderEntity, Long> mhDao = null;
private GenericDao<MapKeyEntity, Long> mkDao = null;
@Test
public void demoBug()
{
try
{
mhDao = new GenericDao<MapHolderEntity, Long>( MapHolderEntity.class );
mkDao = new GenericDao<MapKeyEntity, Long>( MapKeyEntity.class );
MapHolderEntity mh = mhDao.findById( 1L );
MapKeyEntity mk = mkDao.findById( 1L );
// log.info( mh.getMap().get( mk ).getClass() );
Object o = mh.getMap().remove( mk );
log.info( o.getClass() ); // This line outputs some hibernate MarkerObject class name
HbnSessionUtil.rollbackOnly();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
If I hydrate a MapHolderEntity that has a nonempty map of MapKeyEntities to MapValueEntities and immediately call remove() on that map, the object returned by the remove() method is not of the type MapValueEntity, it is of the type org.blah.hibernate.MarkerObject. If I uncomment out the line before the map.remove(), that causes the map to lazy load in. If the map is lazy-loaded in, then map.remove() returns the right thing. If the above snippet behaves the way I'm representing, then I think this is pretty conclusive proof of a problem. Shouldn't PersistentMap.remove() fire off the lazy-loading logic? I can post a zip of all my test entities to a JIRA task if you want.