私は他のプロジェクトで再利用したい機能を持つライブラリを持っています。私の問題は、私のサービスがデータベースに書き込む必要があることです。私の図書館で私のサービスを投入しているプロジェクトのデータソースを使用したいと思います。ここで動的なEntityManagerを第三者のライブラリに挿入する方法
は私のサービスの最小限のセットアップは、私はまた、EntityManagerのプロデューサー
@Singleton
public class CustomEMProducer {
private Map<String, EntityManagerFactory> emfMap = new HashMap<>();
@Produces @Dependent @DynamicDS
public EntityManager produceEntityManager(InjectionPoint injectionPoint) {
String dataSourceName = null;
for(Annotation qualifier: injectionPoint.getQualifiers()) {
if(qualifier instanceof DynamicDS) {
DynamicDS dds = (DynamicDS) qualifier;
dataSourceName = dds.value();
break;
}
}
EntityManagerFactory emf = emfMap.get(dataSourceName);
if (emf == null) {
emf = Persistence.createEntityManagerFactory(dataSourceName);
emfMap.put(dataSourceName, emf);
}
return emf.createEntityManager();
}
@PostConstruct
public void cleanup() {
emfMap.entrySet().stream().forEach(entry -> entry.getValue().close());
}
}
するシングルトンを作成したデータソース
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.FIELD, ElementType.METHOD})
public @interface DynamicDS {
@Nonbinding String value() default "";
}
をオーバーライドするために、カスタム注釈を作成し
@Stateless
public class CustomService {
//to be added in producer
private EntityManager em;
private Principal principal;
//default constructor
public CustomService() {}
//custom constructor called in provider
public CustomService(Principal p, EntityManager e) {
principal = p;
em = e;
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Transactional
public CustomJPAObject createObject(...params...) {
//create JPA Object
em.persist(customObject);
em.flush();
return customObject;
}
}
です
私のサービスプロデューサのコードはこちら
@Stateless
public class CustomServiceProvider {
@Inject private Principal principal;
@Produces @Dependent @DynamicDS
public BackgroundJobService getBackgroundJobService(InjectionPoint injectionPoint) throws EntityManagerNotCreatedException {
Annotation dsAnnotation = null;
for(Annotation qualifier: injectionPoint.getQualifiers()) {
if(qualifier instanceof BackgroundJobDS) {
dsAnnotation = qualifier;
break;
}
}
if (dsAnnotation != null) {
EntityManager em = CDI.current().select(EntityManager.class, dsAnnotation).get();
CustomService service = new CustomService(principal, em);
return service;
}
throw new EntityManagerNotCreatedException("Could not Produce CustomService");
}
}
私は私のコードを配置し、私は次のエラーを取得する注入されたサービスを呼び出すためにしようとすると私の新しいサービス
@Stateless
public class ProjectService {
@Inject @DynamicDS("project-ds") CustomerService service;
public CustomObject create(...params...) {
return service.createObject(...params...);
}
}
を注入しようとするところ以下の通りです:
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1171)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1332)
...
それプロバイダの異なるレベルのすべてが、CustomService.createObject()メソッド呼び出しの@Transactionalがトランザクションを伝播するのを妨げるように見えます。誰がこれがなぜであるか、あるいは動的なEntityManagerを注入する私の目標を達成する別の方法についての洞察を持っていますか?