Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to intercept methods of EntityManager with Seam 3?
    primarykey
    data
    text
    <p>I'm trying to intercept the method <code>persist</code> and <code>update</code> of <code>javax.persistence.EntityManager</code> in a <strong>Seam 3</strong> project.</p> <p>In a previous version (Seam 2) of the micro-framework I'm trying to make, I did this using an implementation of <code>org.hibernate.Interceptor</code> and declaring it in the <code>persistence.xml</code>.</p> <p>But I want something more "CDI-like" now we are in a JEE6 environment.</p> <p>I want that just before entering in a <code>EntityManager.persist</code> call, an event <code>@BeforeTrackablePersist</code> is thrown. The same way, I want an event <code>@BeforeTrackableUpdate</code> to be thrown before entering in a <code>EntityManager.merge</code> call. <code>Trackable</code> is an interface which some of my <code>Entity</code>s could implement in order to be intercepted before persist or merge.</p> <p>I'm using Seam 3 (3.1.0.Beta3) Extended Persistence Manager :</p> <pre class="lang-java prettyprint-override"><code>public class EntityManagerHandler { @SuppressWarnings("unused") @ExtensionManaged @Produces @PersistenceUnit private EntityManagerFactory entityManagerFactory; } </code></pre> <p>So I've made a <code>javax.enterprise.inject.spi.Extension</code>, and tryied many ways to do that :</p> <pre class="lang-java prettyprint-override"><code>public class TrackableExtension implements Extension { @Inject @BeforeTrackablePersisted private Event&lt;Trackable&gt; beforeTrackablePersistedEvent; @Inject @BeforeTrackableMerged private Event&lt;Trackable&gt; beforeTrackableMergedEvent; @SuppressWarnings("unchecked") public void processEntityManagerTarget(@Observes final ProcessInjectionTarget&lt;EntityManager&gt; event) { final InjectionTarget&lt;EntityManager&gt; injectionTarget = event.getInjectionTarget(); final InjectionTarget&lt;EntityManager&gt; injectionTargetProxy = (InjectionTarget&lt;EntityManager&gt;) Proxy.newProxyInstance(event.getClass().getClassLoader(), new Class[] {InjectionTarget.class}, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { if ("produce".equals(method.getName())) { final CreationalContext&lt;EntityManager&gt; ctx = (CreationalContext&lt;EntityManager&gt;) args[0]; final EntityManager entityManager = decorateEntityManager(injectionTarget, ctx); return entityManager; } else { return method.invoke(injectionTarget, args); } } }); event.setInjectionTarget(injectionTargetProxy); } public void processEntityManagerType(@Observes final ProcessAnnotatedType&lt;EntityManager&gt; event) { final AnnotatedType&lt;EntityManager&gt; type = event.getAnnotatedType(); final AnnotatedTypeBuilder&lt;EntityManager&gt; builder = new AnnotatedTypeBuilder&lt;EntityManager&gt;().readFromType(type); for (final AnnotatedMethod&lt;? super EntityManager&gt; method : type.getMethods()) { final String name = method.getJavaMember().getName(); if (StringUtils.equals(name, "persist") || StringUtils.equals(name, "merge")) { builder.addToMethod(method, TrackableInterceptorBindingLiteral.INSTANCE); } } event.setAnnotatedType(builder.create()); } public void processEntityManagerBean(@Observes final ProcessBean&lt;EntityManager&gt; event) { final AnnotatedType&lt;EntityManager&gt; annotatedType = (AnnotatedType&lt;EntityManager&gt;)event.getAnnotated(); // not even called } public void processEntityManager(@Observes final ProcessProducer&lt;?, EntityManager&gt; processProducer) { processProducer.setProducer(decorate(processProducer.getProducer())); } private Producer&lt;EntityManager&gt; decorate(final Producer&lt;EntityManager&gt; producer) { return new Producer&lt;EntityManager&gt;() { @Override public EntityManager produce(final CreationalContext&lt;EntityManager&gt; ctx) { return decorateEntityManager(producer, ctx); } @Override public Set&lt;InjectionPoint&gt; getInjectionPoints() { return producer.getInjectionPoints(); } @Override public void dispose(final EntityManager instance) { producer.dispose(instance); } }; } private EntityManager decorateEntityManager(final Producer&lt;EntityManager&gt; producer, final CreationalContext&lt;EntityManager&gt; ctx) { final EntityManager entityManager = producer.produce(ctx); return (EntityManager) Proxy.newProxyInstance(entityManager.getClass().getClassLoader(), new Class[] {EntityManager.class}, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { final String methodName = method.getName(); if (StringUtils.equals(methodName, "persist")) { fireEventIfTrackable(beforeTrackablePersistedEvent, args[0]); } else if (StringUtils.equals(methodName, "merge")) { fireEventIfTrackable(beforeTrackableMergedEvent, args[0]); } return method.invoke(entityManager, args); } private void fireEventIfTrackable(final Event&lt;Trackable&gt; event, final Object entity) { if (entity instanceof Trackable) { event.fire(Reflections.&lt;Trackable&gt;cast(entity)); } } }); } } </code></pre> <p>In all those observer methods, only the second one (<code>processEntityManagerType(@Observes ProcessAnnotatedType&lt;EntityManager&gt;)</code>) is called ! And even with that binding addition to methods <code>persist</code> and <code>merge</code>, my Interceptor is never called (I've of course enabled it with the correct lines in <code>beans.xml</code>, and enabled my extension with the <code>services/javax.enterprise.inject.spi.Extension</code> file).</p> <p>Something I've thought simple with CDI seems to be actually really hard at last... or perhaps Seam 3 does something which prevent this code from executing correctly...</p> <p>Does someone know how to handle that ?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload