How to lock() a JPA/Hibernate entity when all one has is that entity (no EntityManager/Session)?

404 Views Asked by At

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.

0

There are 0 best solutions below