I am dealing with some legacy code that, in places, does not have a clean and reliable way of obtaining a JPA EntityManager (or Hibernate Session) for a given entity as needed to invoke a lock(...) method on. Essentially we have a method in an entity that needs to do something like:
@Entity
public class SomeEntity {
@Column(...)
@Basic(...)
private String name;
...
public void doSomething(/* arguments irrelevant */) {
...
myCurrentEntityManagerOrSession.lock(...);
...
}
...
}
The question is how to do this - how to get access to that entity manager or session? There are two ways we concocted to accomplish what we need, none desirable even though both work:
Option #1 - embarrassing property flip-flop
final String originalName = getName();
setName("modified " + originalName);
setName(originalName);
... to "trick" Hibernate (we use bytecode enhancement, BTW) to perform the lock itself, then undo the change but keep the lock (we'd do this on any "inexpensive" property).
Option #2: Inappropriate abuse of reflection of Hibernate bytecode enhancements and its internal API
private static final Method HIBERNATE_ENTITY_ENTRY_GETTER;
static {
Method getter;
try {
getter = SomeEntity.class.getMethod("$$_hibernate_getEntityEntry");
} catch (NoSuchMethodException e) {
/// Oooh .. not good!
getter = null;
}
HIBERNATE_ENTITY_ENTRY_GETTER = getter;
}
public Session getEntitySession() {
try {
final MutableEntityEntry entry = (MutableEntityEntry) HIBERNATE_ENTITY_ENTRY_GETTER.invoke(this);
return (Session) entry.getPersistenceContext().getSession();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void lock(final LockMode lockMode) {
getEntitySession().lock(this, lockMode);
}
public void lock() {
lock(LockMode.OPTIMISTIC_FORCE_INCREMENT);
}
Is there a proper, clean way to obtain an EntityManager / Session that currently manages/owns a specific entity? We know that the underlying engine has to know this already, of course... but it seems that this is well hidden away.
ADDITIONAL NOTE: ThreadLocal may be an answer in some projects but not in this one. Don't ask.