Seam3プロジェクトでメソッドpersist
とupdate
のをインターセプトしようとしています。javax.persistence.EntityManager
私が作成しようとしているマイクロフレームワークの以前のバージョン(Seam 2)では、の実装を使用してこれを実行し、org.hibernate.Interceptor
で宣言しましたpersistence.xml
。
しかし、私はJEE6環境にいるので、もっと「CDIのような」ものが欲しいです。
電話をかける直前にEntityManager.persist
イベント@BeforeTrackablePersist
がスローされるようにしたいと思います。@BeforeTrackableUpdate
同様に、電話に出る前にイベントをスローしたいのですEntityManager.merge
が。は、永続化またはマージする前にインターセプトするためにTrackable
、一部のユーザーが実装できるインターフェイスです。Entity
Seam 3(3.1.0.Beta3)Extended Persistence Managerを使用しています:
public class EntityManagerHandler {
@SuppressWarnings("unused")
@ExtensionManaged
@Produces
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
}
だから私はを作り、javax.enterprise.inject.spi.Extension
それを行うために多くの方法を試しました:
public class TrackableExtension implements Extension {
@Inject @BeforeTrackablePersisted
private Event<Trackable> beforeTrackablePersistedEvent;
@Inject @BeforeTrackableMerged
private Event<Trackable> beforeTrackableMergedEvent;
@SuppressWarnings("unchecked")
public void processEntityManagerTarget(@Observes final ProcessInjectionTarget<EntityManager> event) {
final InjectionTarget<EntityManager> injectionTarget = event.getInjectionTarget();
final InjectionTarget<EntityManager> injectionTargetProxy = (InjectionTarget<EntityManager>) 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<EntityManager> ctx = (CreationalContext<EntityManager>) 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<EntityManager> event) {
final AnnotatedType<EntityManager> type = event.getAnnotatedType();
final AnnotatedTypeBuilder<EntityManager> builder = new AnnotatedTypeBuilder<EntityManager>().readFromType(type);
for (final AnnotatedMethod<? super EntityManager> 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<EntityManager> event) {
final AnnotatedType<EntityManager> annotatedType = (AnnotatedType<EntityManager>)event.getAnnotated();
// not even called
}
public void processEntityManager(@Observes final ProcessProducer<?, EntityManager> processProducer) {
processProducer.setProducer(decorate(processProducer.getProducer()));
}
private Producer<EntityManager> decorate(final Producer<EntityManager> producer) {
return new Producer<EntityManager>() {
@Override
public EntityManager produce(final CreationalContext<EntityManager> ctx) {
return decorateEntityManager(producer, ctx);
}
@Override
public Set<InjectionPoint> getInjectionPoints() {
return producer.getInjectionPoints();
}
@Override
public void dispose(final EntityManager instance) {
producer.dispose(instance);
}
};
}
private EntityManager decorateEntityManager(final Producer<EntityManager> producer, final CreationalContext<EntityManager> 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<Trackable> event, final Object entity) {
if (entity instanceof Trackable) {
event.fire(Reflections.<Trackable>cast(entity));
}
}
});
}
}
これらすべてのオブザーバーメソッドでは、2番目のメソッド(processEntityManagerType(@Observes ProcessAnnotatedType<EntityManager>)
)のみが呼び出されます。そして、メソッドpersist
とへのそのバインディングの追加があってもmerge
、私のインターセプターは決して呼び出されません(もちろん、の正しい行でそれをbeans.xml
有効にし、ファイルで私の拡張子を有効にしましたservices/javax.enterprise.inject.spi.Extension
)。
私がCDIで単純だと思っていたことが、ついに実際には本当に難しいように思えます...またはおそらくSeam 3は、このコードが正しく実行されないようにする何かをします...
誰かがそれを処理する方法を知っていますか?