Providing EntityManager by an #ConversationScoped method - java-ee-6

I tried to run the simple JEE6 application generated by maven archetype groupId: org.fluttercode.knappsack , artifactID: jee6-sandbox-archetype in JBoss7.
(went through this turial, sorry, in German)
However, when calling the welcome JSF, I get the following error message:
org.jboss.weld.exceptions.IllegalProductException: WELD-000053 Producers
cannot declare passivating scope and return a non-serializable class:
[method] #Produces #DataRepository #ConversationScoped
public org.rap.jee6project.bean.DataRepositoryProducer.getEntityManager()
org.jboss.weld.bean.AbstractProducerBean.checkReturnValue(AbstractProducerBean.java:264)
org.jboss.weld.bean.AbstractProducerBean.create(AbstractProducerBean.java:362)
org.jboss.weld.context.AbstractContext.get(AbstractContext.java:122)
Indeed, the DataRepositoyProducer class which is supposed to return an EntityManager instance, is defined an annotated as follws:
#Stateless
public class DataRepositoryProducer {
private EntityManager entityManager;
#Produces #DataRepository #ConversationScoped
public EntityManager getEntityManager() {
return entityManager;
}
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
If I use #RequestScoped, the application runs as promised. I wonder why other people who went through this tutorial didn't experience this problem? And how to fix it properly (using #RequestScoped means that the bean is recreated for each user request, right?, which I expect to be not very efficient)
The official JEE6 Tutorial says: "Beans that use session, application, or conversation scope must be serializable, but beans that use request scope do not have to be serializable" . However, that does not seem to be the problem here, since the server is not comlaining about the bean not serializable but the product of the producer bean.

It should be..
#Stateful
#ConversationScoped
public class ProducerCreator implements Serializable{
#PersistenceConText
private EntityManager entityManager;
....
}
and if you want to use the same entity context in of each conversation it should be
#PersistenceContex(type = PersistenceContextType.EXTENDED)
finally, If you want to have service layer, should create stateful and inject to conversation bean

I had same problem running the demo on a jboss7.
Just remove #ConversationScoped at getEntityManager() did the trick to me to let it deploy.
Even though there are some flaws:
javax.servlet.ServletException: javax.faces.component.StateHolderSaver cannot be cast to [Ljava.lang.Object;
javax.faces.webapp.FacesServlet.service(FacesServlet.java:606)
org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:62)
I don't know exactly, if it is related, but I guess so.

Remember: EntityManager is not serializable, so it cannot be stored in ConversationScope

Related

JPA EntityManager.flush() is not called by java/jakarta EE container

JPA EntityManager.flush() is not called by glassfish 5.1 EE container.
In Java SE environment:
EntityTransaction t = em.getTransaction();
t.begin();
// persist entities
em.persist(entity);
t.commit();
commit() will flush entities in persistence context.
Java EE environment e.g. Glassfish:
#Stateless
public class DataManagerBean {
#PersistenceContext
EntityManager em;
public void persist(Object entity) {
em.persist(entity);
}
}
JSF Bean:
#Named
#ViewScoped
public class FooBean {
#EJB
DataManagerBean dataManagerBean;
public void createFoo() {
dataManagerBean.persist(foo);
}
}
Application can not call em.getTransaction(). Transaction is managed by container. JPA provider entityManager.flush() is not called before entityManager.close() is called. As a result the entity is not created in database.
In EE environment, the database connection obtained by JPA provider EntityManager is the same as one used by container?
How does EE container tell JPA provider to flush entities to persistence if flush() is not called?
It is dependant on the way you calling your business method. In one word, beeing defaulted -- transaction begins when your flow enters FIRST business method (or Interceptor, decorating your first business method) and ends when your flow leaves last business method in the stack (or Interceptor, decorating your first business method).
You can manage transactions using #TransactionAttribute annotation with appropriate TransactionAttributeType (REQUIRED is default if not annotated). For example:
#Stateless
public class DataManagerBean {
#PersistenceContext
EntityManager em;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void persist(Object entity) {
em.persist(entity);
}
}
In this case being called DataManagerBean.persist starts new transaction and commit and flush changes when being leaved. In case of error it will roll transaction back and throw exception you can catch at calling business method.

Injecting a Stateless EJB into another Stateless and using PersistenceContext

With JEE 5 / EJB 3.0 life of Java developers became much more easier. Later, influenced by Spring and CDI, similar approaches were also adopted in JEE.
Now, I hope I am doing it right, but just to be sure:
I have several Stateless EJBs, which all query and / or modify the database. An example is
#Stateless
public class AddressDBService {
#PersistenceContext
protected EntityManager em;
Some of the Stateless EJB refer the other services like this:
#Stateless
public class AVeDBService {
#PersistenceContext
protected EntityManager em;
#Inject
private HomeToDealDBService homeToDealDBService;
#Inject
private AddressDBService addressDBservice;
and in the Stateless EJBs I have public methods like the ones below:
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void saveEntity(Home home) throws EntityExistsException {
this.em.persist(home);
addressDBservice.saveAddress(home.getMainAddress(), home);
}
While I am almost certain this usage is correct and thread-safe (the above services are in turn injected into JSF Managed Beans).
Could somebody confirm that my usage is correct, thread-safe and conforms good practices?
My usage seems to be conform with the following questions:
Is EntityManager really thread-safe?
Stateless EJB with more injected EJBs instances
The "is correct?" question can't be answered without know the goal of the project.
It could works? Yes, you have posted java-ee code that could deploy, but is not enough.
I usually use BCE (Boundary Control Entity) pattern and Domain Driven pattern.
In this pattern we use EJB for business logic services or endpoint (JAX-RS) and all other injections, that are the Control part, are CDI objects.
Entities (JPA) could use cascade to avoid to manually save related entities:
addressDBservice.saveAddress(home.getMainAddress(), home);
can be avoided if you define the entity like this:
#Entity
public class Home {
#ManyToOne(cascade=ALL)
private Address mainAddress;
}
The #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) annotation usually respond to a specific transactions behavior, is not required, so is correct only if is what you want to do.

Injection in entity listener with Quarkus

I'm trying to inject a bean into an entity listener in a Quarkus-application:
#ApplicationScoped
public class MyEntityListener implements Serializable {
#Inject
MyService service;
#PrePersist
#PreUpdate
public void checkWrite(BaseEntity entity) {
service.check(entity);
}
}
But service is always null. Changing scope to #SessionScoped has no effect.
According to this 2 SO-discussions, this should be possible:
CDI injection in EntityListeners
How can I use an EJB in a EntityListener?
I couldn't find any information about which JPA-version Quarkus is using, but since it is a state-of-the-art-framework I think it is JPA 2.1?
So should this be possible and if yes, what am I doing wrong?
I found a Quarkus-issue addressing this problem: https://github.com/quarkusio/quarkus/issues/6948
Seems like Quarkus is lacking support for this feature and maybe it will be implemented in the future. There's also a workaround described.

JPA and EJB - When do I need to use transaction?

I'm learning persistence in Java following some tutorial.
I'm using Java EE 7 and Payara server.
I noticed that each uses a different method for persistence.
Examples:
simple
#Stateless
public class BookServiceBean implements BookService {
#PersistenceContext
private EntityManager em;
public void createOrUpdate(Book book) {
em.persist(book);
}
public void remove(Book book) {
em.remove(book);
}
}
with flush(), this is used when validation strategy isn't set on "AUTO" in persistene.xml, right?
#Stateless
public class BookServiceBean implements BookService {
#PersistenceContext
private EntityManager em;
public void createOrUpdate(Book book) {
em.persist(book);
em.flush();
}
public void remove(Book book) {
em.remove(book);
em.flush();
}
}
with transaction
#Stateless
public class BookServiceBean implements BookService {
#PersistenceContext
private EntityManager em;
public void createOrUpdate(Book book) {
utx.begin();
em.persist(book);
utx.commit();
}
public void remove(Book book) {
utx.begin();
em.remove(book);
utx.commit();
}
}
When and why do I have to use the last one?
Is it necessary to use em.close() at the end of each method?
What are the good practices?
The first one, an EJB method without all that manual flush and transaction fuzz, is the canonical approach. A single EJB method call counts by default already as a single full transaction. The EJB container will transparently begin the transaction before the method is invoked and commit the transaction when the method returns (or rollback when an application exception is thrown from the method).
The manual flush in second example is unnecessary. Generally, you want to use em.flush() only when you're modifying an entity (i.e. making it "dirty") and want afterwards (indirectly) perform a SELECT on it within the very same transaction. It's rare, but there are real world use cases for it, generally when you'd like to SELECT a parent whose the dirty entity is a child of.
The manual transaction management in third example is totally unnecessary. You should already realize that after having read the first paragraph. Manual transaction management is only necessary when you aren't using JTA, but RESOURCE_LOCAL (usually, in Java SE not Java EE).
See also:
When is it necessary or convenient to use Spring or EJB3 or all of them together?
JSF request scoped bean keeps recreating new Stateful session beans on every request?
Handling service layer exception in Java EE frontend method

Custom Annotation vs using #Named in JEE6

Is there any difference between these two alternatives ... can they both be used interchangeably?
(A) Creating a custom annotation so #Inject can be used instead of #PersistenceContext within a DAO, as shown in the answer to - how-to-stack-custom-annotation-in-java-with-inject-annotation
(B) Using #Named("yourName") to qualify the Producer, such as the following code sample.
public class Resources {
/**
* EntityManager's persistence context is defined here so the #Inject annotation may be used in referencing classes.
*/
#Produces
#Named("MyEm")
#PersistenceContext(unitName = "jboss.managed")
private EntityManager em;
}
#Stateless
public class FiletracksentHome {
..
#Inject
#Named("MyEm")
private EntityManager entityManager;
..
}
They are interchangable, but you should use (A).
The #Named annotation is primarily used for being able to access the object via expression language (EL), e.g. in a JSF view.
The problem is, that the resolution is done via String, thus being neither type safe, nor usually being automatically covered by refactorings in the IDE.
The CDI specification states that it should not be used for qualifying injection points if not be used to integrate legacy code.
Here's a nice article about this topic.