0

Seam3プロジェクトでメソッドpersistupdateのをインターセプトしようとしています。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は、このコードが正しく実行されないようにする何かをします...

誰かがそれを処理する方法を知っていますか?

4

2 に答える 2

1

あなたはこれを必要以上に難しくしていると思います。ただし、最初に、Java EE 6ではJPAとCDIの統合はあまり良くありませんが、JavaEE7とJPA2.1での変更を強く望んでいます。

EntityManagerの実際のインスタンスに委任するだけでなく、関心のあるメソッドを呼び出すときに独自のイベントを発生させるEntityManagerの独自のプロデューサーを作成します。SeamPersistenceを確認してください。これを行うことができる1つの方法を確認するためのソース。

于 2011-11-22T04:58:24.543 に答える
0

最後に、Seam Persistenceの小さなパッチがSEAMPERSIST-75に適用されたので、理論的には、メソッドを拡張org.jboss.seam.persistence.HibernatePersistenceProviderしてオーバーライドすることでそれを行うことができますproxyEntityManager(EntityManager)

于 2012-01-03T14:46:29.393 に答える