Migrating javaee6 to javaee7: error WELD-001408 Unsatisfied dependencies - annotations

Actually, I'm migrating an application from javaee6 to javaee7 which has ejb module with some CDI components and all business logic.
In general, I had an interface to make CRUD with entities:
public interface StoreManager<T> {
T create(T entity) throws SystemException;
}
And an implementation like this:
public class StoreManagerImpl extends AbstractManager<Object> implements StoreManager<Object> {
#PersistenceContext(unitName="PersistUnit")
private EntityManager em;
private void setEntityManager(EntityManager em) {
this.em = em;
}
#Override
protected EntityManager getEntityManager() {
return em;
}
#Produces #Generator
public StoreManager create() {
StoreManagerImpl smImpl = new StoreManagerImpl();
smImpl.setEntityManager(em);
return smImpl;
}
}
The abstract class AbstractManager is where are defined all methods like create, read, update,etc.
public abstract class AbstractManager<T> {
public AbstractManager() {
}
protected abstract EntityManager getEntityManager();
public <P> P crear(P entity, Class<?> clase) throws SystemException {
try {
getEntityManager().persist(entity);
getEntityManager().flush();
getEntityManager().refresh(entity);
} catch (EntityExistsException ex) {
throw new EntityExistsException("El registro ya existe en la base de datos.");
} catch (EJBException ex) {
throw new SystemException("El registro no pudo ser guardado.");
} catch (Exception ex) {
ex.printStackTrace();
throw new SystemException("El registro no pudo ser guardado.");
}
return entity;
}
}
My #Generator is a Java annotation that will provide a way for services to call operations passing an entity through generic to field level. That is:
#Inject
#Generator
private StoreManager<Person> storeManager;
...
..
storeManager.create(person);
....
With glassfish 3 and javaee7 everything is working, but javaee7 seems to have some specifications that doesn't make possible my implementation. Does anyone know about this problem or could help me to solve?
Thanks a lot
and sorry for my poor english.........

You're correct, there is a change in the spec that makes your original code not work. I believe the issue is under review in CDI 1.2 to be reverted. Basically, the way CDI 1.1 is written you have to have a concrete implementation of StoreManager<Person> (e.g. PersonStoreManager extends StoreManagerImpl<Person>).

Related

How to configure Entity Manager dependency injection on Jersey

I have a Java web application running on Tomcat 9.
It uses the tools: Primefaces 10, JSF 2, CDI, EclipseLink.
This application is modularized as follows:
model
dao
service
managedBean
web
I created another modules
microservice
restful
where the "restful module" is the jsersey restful webservice.
I incorporate this webservice with the "service", "dao" and "model" modules using dependency injection (CDI) binding through this class
public class MyApplicationBinder extends AbstractBinder {
// mapping dependency injection with jersey
#Override
protected void configure() {
//bind(MicroserviceDataImpl.class).to(MicroserviceDataImpl.class); // concrete class
bind(SequenceRuleImpl.class).to(SequenceRule.class); // class implementing interface
bind(CaracteristicaMS.class).to(new TypeLiteral<Microservice<CaracteristicaDTO>>(){}); // classe implementing interface with generics
bind(MSCaracteristicaDaoImpl.class).to(new TypeLiteral<Dao<Caracteristica>>(){}).qualifiedBy(new Qualifier.DaoMSCaracteristica()); // class implementing interface with generics and qualifier
}
}
My qualifier
public class Qualifier {
public static class DaoMSCaracteristica extends AnnotationLiteral<DaoType> implements DaoType {
#Override
public TipoClasse value() {
return TipoClasse.CARACTERISTICA;
}
}
}
My resource
#RequestScoped #Path("/caracteristica")
public class CaracteristicaRestful {
#Inject
private Microservice<CaracteristicaDTO> cms;
// other attributes and methods
}
My microservice class
#Dependent
public class CaracteristicaMS implements Microservice<CaracteristicaDTO>, Serializable {
#Inject #DaoType(TipoClasse.CARACTERISTICA)
private Dao<Caracteristica> cd;
// others attributes and methods
}
My dao class
#Dependent #Default #DaoType(value = TipoClasse.CARACTERISTICA)
public class CaracteristicaDaoImpl extends AbsDao<Caracteristica> implements Dao<Caracteristica>, Serializable {
#NotNull #Inject #PersistenceUnitNameType(CADMAT_PU)
EntityManagerFactory emf;
// others attributes and methods
}
My Entity Manager factory provider
#ApplicationScoped
public class EMFProvider {
public static final EntityManagerFactory EMF_CADMAT = Persistence.createEntityManagerFactory(CADMAT_PU);
public static final EntityManagerFactory EMF_SIAFNET = Persistence.createEntityManagerFactory(SIAFEM_PU);
#Produces #Dependent #PersistenceUnitNameType(SIAFEM_PU)
public EntityManagerFactory getEMF_SIAFNET() {
return EMF_SIAFNET;
}
#Dependent #PersistenceUnitNameType(SIAFEM_PU)
public void closeENF_SIAFNET(#Disposes #PersistenceUnitNameType(SIAFEM_PU) EntityManagerFactory emf) {
if (emf != null && emf.isOpen()) {
Logger.getAnonymousLogger().log(Level.INFO, "***** closing em {0}", emf);
emf.close();
}
}
#Produces #ApplicationScoped #PersistenceUnitNameType(CADMAT_PU)
public EntityManagerFactory getEMF_CADMAT() {
return EMF_CADMAT;
}
#Produces #Dependent #PersistenceUnitNameType(CADMAT_PU)
public EntityManager getEM() {
EntityManager em = EMF_CADMAT.createEntityManager();
Logger.getAnonymousLogger().log(Level.INFO, "***** creating em {0}", em);
return em;
}
#ApplicationScoped #PersistenceUnitNameType(CADMAT_PU)
public void close(#Disposes #PersistenceUnitNameType(CADMAT_PU) EntityManagerFactory emf) {
if (emf != null && emf.isOpen()) {
Logger.getAnonymousLogger().log(Level.INFO, "***** closing em {0}", emf);
emf.close();
}
}
#Dependent #PersistenceUnitNameType(CADMAT_PU)
public void close(#Disposes #PersistenceUnitNameType(CADMAT_PU) EntityManager em) {
if (em != null && em.isOpen()) {
Logger.getAnonymousLogger().log(Level.INFO, "***** closing em {0}", em);
em.close();
}
}
}
My transactional interceptor
#Interceptor #TransactionType
public class TransactionalInterceptor {
#AroundInvoke
public Object transactional(InvocationContext ctx) throws Exception {
EntityManager em = null;
Field field = null;
try {
field = ctx.getMethod().getDeclaringClass().getDeclaredField("em");
} catch (NoSuchFieldException e1) {
try {
field = ctx.getMethod().getDeclaringClass().getSuperclass().getDeclaredField("em");
} catch (NoSuchFieldException e2) {
throw new IllegalStateException("invalid interceptor configuration for " + ctx.getMethod().getDeclaringClass());
}
}
field.setAccessible(true);
em = (EntityManager)field.get(ctx.getTarget());
if (em == null) throw new IllegalStateException("*** no em for transaction");
Logger.getAnonymousLogger().info("*** transaction em " + em);
Dao.begin(em);
Object obj = ctx.proceed();
Dao.commit(em);
return obj;
}
}
My interface annotation classes
#Qualifier #Retention(RetentionPolicy.RUNTIME) #Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface DaoType {
public TipoClasse value();
}
#Qualifier #Retention(RetentionPolicy.RUNTIME) #Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface PersistenceUnitNameType {
public String value();
}
Is there a way to bind my EntityManager using this structure?

#Inject - UserTransaction throws weld error

Error:
Exception 1 :
org.jboss.weld.exceptions.DefinitionException: WELD-001451: javax.transaction.UserTransaction cannot be injected into an enterprise bean with container-managed transactions: [BackedAnnotatedField] #Inject com.evry.integrator.snow.model.dao.impl.GenericDaoImpl.userTransaction
at com.evry.integrator.snow.model.dao.impl.GenericDaoImpl.userTransaction(GenericDaoImpl.java:0)
StackTrace
at org.jboss.weld.module.ejb.WeldEjbValidator.validateInjectionPointForDefinitionErrors(WeldEjbValidator.java:40)
at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDefinitionErrors(Validator.java:336)
Code:
public abstract class GenericDaoImpl<T, PK> implements GenericDao<T, PK> {
private static final Logger LOG = Logger.getLogger(GenericDaoImpl.class.getName());
#PersistenceContext(unitName = "IntegratorMasterdataDS")
protected EntityManager em;
#Inject
UserTransaction userTransaction
Scrutiny Class
#Stateless
public class Scrutiny {
private static final Logger log = Logger.getLogger(Scrutiny.class.getName());
public Scrutiny() {
System.out.println("Scrutiny");
}
#Inject
StatusDao statusDao;
public JobStatus insertNewRecord(JobName jName) {
log.info("insertNewRecord:" + jName);
try {
statusDao.beginUserTransaction(); <--- Here i want to begin
statusDao.create(js);
statusDao.flush();
statusDao.commitUserTransaction(); <--- Here i want to Commit
} catch (Exception e) {
log.warning("insertNewRecord:" + e);
}
Status Dao:
public interface StatusDao extends GenericDao<JobStatus, String> {
List<JobStatus> checkExistingRecordToday(JobName jName);
}
Job Status Dao:
#Stateless
public class JobStatusDaoImpl extends GenericDaoImpl<JobStatus, String> implements StatusDao {
private static final Logger LOG = Logger.getLogger(JobStatusDaoImpl.class.getName());
#Override
public List<JobStatus> checkExistingRecordToday(JobName jName) {
As of now whole process is handled by JTA but i want to commit Scrutiny class instantantly which suggest job has just started and at end want to update the same.
You should remove the UserTransaction injection from your DAO generic object and handle the transaction within Scrutiny bean, annotating it with TransactionManagement.
Your bean code should become this:
#Stateless
#TransactionManagement(value=TransactionManagementType.BEAN)
public class Scrutiny {
private static final Logger log = Logger.getLogger(Scrutiny.class.getName());
#Inject
private UserTransaction utx;
public Scrutiny() {
System.out.println("Scrutiny");
}
#Inject
StatusDao statusDao;
public JobStatus insertNewRecord(JobName jName) {
log.info("insertNewRecord:" + jName);
try {
utx.begin(); <--- Here i want to begin
statusDao.create(js);
utx.flush();
utxcommit(); <--- Here i want to Commit
} catch (Exception e) {
log.warning("insertNewRecord:" + e);
}
}
With these changes, your DAO should continue to work using container managed transactions, while your specific bean can control the transaction as desired.

How to change my DAO Bean from EJB to pure CDI?

I want to reuse my AbstractDAO in a new project, except this time I don't want to use EJB annotations - just CDI ones.
So far, I've been using it like this:
public abstract class AbstractDAO<T> {
#PersistenceContext(unitName = "myUnit")
private EntityManager entityManager;
private Class<T> entityClass;
public AbstractDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected EntityManager getEntityManager() {
return entityManager;
}
public void save(T entity) {
entityManager.persist(entity);
}
public void update(T entity) {
entityManager.merge(entity);
}
public void remove(T entity) {
entityManager.remove(entityManager.merge(entity));
}
public T findById(Object id) {
return entityManager.find(entityClass, id);
}
public List<T> findBy(String attrName, Object attrValue) {
// Impl here
}
// [...] Many more search methods
}
And I've been creating a DAO for each Entity, like this for example:
#Stateless
public class UserDAO extends AbstractDAO<User> {
public UserDAO() {
super(User.class);
}
public User findByUsername(String username) {
if (username != null) {
return super.findOneBy("username", username.toLowerCase());
}
return null;
}
}
Now I would like to get rid of the #Stateless annotation. But simply replacing it with a #RequestScoped one won't work because of the non-private constructor with no parameters requirement of JSR-346
How can I refactor my DAO to a pure CDI one ?
Two issues here: CDI beans are not transaction aware by default -unlike EJBs, so you will have to use #Transactional qualifier if you want to do saves/updates...
Second, your no-arg constructor: you only need to pass the entity class to your abstract class even though you also specify it as a generic argument. You can infer the actual class like this:
public class AbstractDAO<T> {
private transient Class<T> entityClass;
#SuppressWarnings("unchecked")
public AbstractDAO() {
Type generSuperCls = getClass().getGenericSuperclass();
if (generSuperCls instanceof Class) {
generSuperCls = ((Class<?>) generSuperCls).getGenericSuperclass();
}
ParameterizedType parameterizedType = (ParameterizedType) generSuperCls;
Type type = parameterizedType.getActualTypeArguments()[0];
if (type instanceof Class) {
this.entityClass = (Class<T>) type;
} else if (type instanceof ParameterizedType) {
this.entityClass = (Class<T>) ((ParameterizedType) type).getRawType();
}
}
#PersistenceContext
private EntityManager em;
public T getById(Object id) throws ServiceException {
return getEm().find(entityClass, id);
}
// other methods follow
}
As a side note, why do you want to get rid of EJBs? Benchmarks show you get better performance using pooled slsb than cdi and they together very well(every EJB beans is also a CDI bean in jee container).

How to inject dynamic EntityManager into a Third Party Library

I have a library with some functionality that I want to reuse in other projects. My issue is that my service requires writing to the database. I would like for my library to use the datasource of the project that is inject my service.
Here is the minimal setup of my service
#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;
}
}
I created a Custom Annotation for overriding the datasource
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE,ElementType.FIELD, ElementType.METHOD})
public #interface DynamicDS {
#Nonbinding String value() default "";
}
I also created a Singleton to be an EntityManager Producer
#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());
}
}
Here is the code for my Service Producer
#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");
}
}
The following is where I try to inject my new service
#Stateless
public class ProjectService {
#Inject #DynamicDS("project-ds") CustomerService service;
public CustomObject create(...params...) {
return service.createObject(...params...);
}
}
When I deploy my code and attempt to call the injected service I get the following error:
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)
...
It looks like all of the different levels of providers are preventing the #Transactional on the CustomService.createObject() method call from propagating the transaction. Does anyone have insight into why this is or an alternate way of accomplishing my goal of injecting a dynamic EntityManager?
After much experimenting, I was unable to get dynamically generate an EntityManager through the above code. After much research, I gave up on trying to pass in the name from outside the 3rd part library. I would up creating the following interface:
public interface CustomEntityManager {
EntityManager getEntityManager();
}
This meant that inside the project that uses the 3rd party service I can do the create the following implementation to inject the EntityManager
public ProjectSpecificEntityManager implements CustomEntityManager {
#PersistenceContext(unitname = "project-ds")
private EntityManager em;
public EntityManager getEntityManager() {
return em;
}
}
I had to update my CustomService to the following
#Stateless
public class CustomService {
//Ignore warning about no bean eligible because it is intended
//that the project that uses this library will provide the
//implementation
#SuppressWarnings("cdi-ambiguous-dependency")
#Inject
CustomEntityManager cem;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#Transactional
public CustomJPAObject createObject(...params...) {
//create JPA Object
cem.getEntityManager().persist(customObject);
return customObject;
}
}

EJB TransactionRolledBackException is not catched

I have code like in the snippet below. Question is: Why I can't catch the exception in method1, instead doSomeOtherStuff() is called (which should be prevented in case of an exception)
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class EJBBean1 {
#EJB
private EJBBean2 ejb2;
public void method1(Produkt p){
try {
ejb2.method2(p)
doSomeOtherStuff();//is always called
}
catch(Exception e) {
//e is never catched here!!!
}
}
}
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class EJBBean2 {
#PersistenceContext(unitName = "scm")
protected EntityManager em;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void method2(Produkt p) {
em.merge(p)//Exception rises here (in merge)
}
}
Ok, answer my own question ;-)
Exception does rise in em.merge(), but is not thrown immediately. The JPA container decides when to flush() the merge().
If I change the code a bit:
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void method2(Produkt p) {
em.merge(p)
em.flush();//Exception rises here
}
I can catch the Exception immediatly.