I am just starting to work with JPA. Based on several tutorials, I have built a simple dynamic web project that includes a GerericDAO as well as a singleton that encapsulates the EntityManagerFactory.
public class PersistenceManager {
private static final PersistenceManager instance = new PersistenceManager();
protected EntityManagerFactory emf;
public static PersistenceManager getInstance() {
return instance;
}
private PersistenceManager() {
}
public EntityManagerFactory getEntityManagerFactory() {
if (emf == null)
createEntityManagerFactory();
return emf;
}
public void closeEntityManagerFactory() {
if (emf != null) {
emf.close(); emf = null;
}
}
protected void createEntityManagerFactory() {
this.emf = Persistence.createEntityManagerFactory("Fusion");
}
}
public class GenericJPADAO<ID extends Serializable, T> implements GenericDAO<ID, T> {
private Class<T> persistentClass;
private EntityManager entityManager;
#SuppressWarnings("unchecked")
public GenericJPADAO() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
protected EntityManager getEntityManager() {
if (entityManager == null)
throw new IllegalStateException("EntityManager has not been set on DAO before");
return entityManager;
}
public T create(T element) throws IOException, IllegalArgumentException {
if (element == null)
throw new IllegalArgumentException();
try {
getEntityManager().persist(element);
return element;
} catch (Exception e) {
throw new IOException("create failed");
}
}
To pull this together in a Transaction method I need something like this (leaving out some of the detail):
DAOFactory factory = DAOFactory.instance(DAOFactory.JPA);
ConfigurationDAO dao = factory.getAddressDAO();
dao.setEntityManager(entityManager);
EntityTransaction ut = entityManager.getTransaction();
try {
ut.begin();
dao.create(address);
ut.commit();
} catch (Exception e) {
ut.rollback();
}
finally {
close??
}
I am very new to this, however it seems awkward to be setting the EntityManager in the DAO Class from the Transaction method. I have previously worked with Hibernate and my DAO classes have been able to retrieve a current Session from a HibernateUtil type class. I am not sure how to achieve a similar structure with JPA / EntityManager whilst maintaining a Thread safe application? Maybe my structure is poorly designed - anyway any advice / guidance much appreciated. I have not been able to find a clear complete example of this. By the way - I am not using Spring in this application.
JPA specification defines a pattern similar to Hibernate's getCurrentSession() - the current EntityManager is injected into field annotated with #PersistenceContext.
However, specification says that support for this pattern should be provided by external environment rather than by JPA providers, therefore you cannot just use it in standalone environment.
In particular, this pattern is supported by Spring Framework and Java EE application servers.
Alternatively, if you cannot use Spring Framework or Java EE application server you can emulate this pattern by storing the current EntityManager in ThreadLocal.
Related
I have a service with a persistence setup using JPA, Hibernate and Guice (if it's useful, I'm not using Spring). This is the first, working version of my code:
public class BookDao {
#Inject
protected Provider<EntityManager> entityManagerProvider;
protected EntityManager getEntityManager() {
return entityManagerProvider.get();
}
#Transactional
public void persist(Book book) {
getEntityManager().persist(book);
}
}
public class MyAppModule extends AbstractModule {
#Override
protected void configure() {
initializePersistence();
}
private void initializePersistence() {
final JpaPersistModule jpaPersistModule = new JpaPersistModule("prod");
jpaPersistModule.properties(new Properties());
install(jpaPersistModule);
}
}
But now I need to configure multiple persistence units. I'm following the advice in this mailing list, and according to them, I should move my module logic to a private module. I did as suggested and created a second version of the same code, the changes are commented below:
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target({ FIELD, PARAMETER, METHOD })
public #interface ProductionDataSource {} // defined this new annotation
public class BookDao {
#Inject
#ProductionDataSource // added the annotation here
protected Provider<EntityManager> entityManagerProvider;
protected EntityManager getEntityManager() {
return entityManagerProvider.get();
}
#Transactional
public void persist(Book book) throws Exception {
getEntityManager().persist(book);
}
}
public class MyAppModule extends PrivateModule { // module is now private
#Override
protected void configure() {
initializePersistence();
// expose the annotated entity manager
Provider<EntityManager> entityManagerProvider = binder().getProvider(EntityManager.class);
bind(EntityManager.class).annotatedWith(ProductionDataSource.class).toProvider(entityManagerProvider);
expose(EntityManager.class).annotatedWith(ProductionDataSource.class);
}
private void initializePersistence() {
JpaPersistModule jpaPersistModule = new JpaPersistModule("prod");
jpaPersistModule.properties(new Properties());
install(jpaPersistModule);
}
}
The newly annotated EntityManager is being correctly injected by Guice and is non-null, but here's the fun part: some of my unit tests started failing, for example:
class BookDaoTest {
private Injector injector;
private BookDao testee;
#BeforeEach
public void setup() {
injector = Guice.createInjector(new MyAppModule());
injector.injectMembers(this);
testee = injector.getInstance(BookDao.class);
}
#Test
public void testPersistBook() throws Exception {
// given
Book newBook = new Book();
assertNull(newBook.getId());
// when
newBook = testee.persist(newBook);
// then
assertNotNull(newBook.getId()); // works in the first version, fails in the second
}
}
In the first version of my code the last line above just works: the entity is persisted and has a new id. However, in the second version of my code (using a PrivateModule and exposing an annotated EntityManager from it) the persist() operation doesn't work anymore, the entity is without an id. What could be the problem? I didn't do any other configuration changes in my environment, and I don't see error messages in the logs. Let me know if you need more details.
It turns out that the problem was the #Transactional annotation. In the first version of my code, Guice automatically adds interceptors for managing the transaction. By doing a debug, I found out that before executing my persist(Book book) method, Guice calls the following method from the com.google.inject.internal.InterceptorStackCallback package:
public Object intercept(Object proxy, Method method, Object[] arguments, MethodProxy methodProxy)
In the second version of my code, when I exposed the persistence unit from a private module the above interceptor was no longer called, leaving my persist operation without transaction handling. This is a known issue and is by design.
As a workaround I had to implement transactions by hand, making my code more verbose. I also had to change the way the entity manager is injected. This solution worked for me:
public class BookDao {
#Inject
#Named(PROD_PERSISTENCE_UNIT_NAME)
private EntityManagerFactory entityManagerFactory;
private EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}
public void persist(Book book) throws Exception {
EntityManager em = getEntityManager();
try {
em.getTransaction().begin();
em.persist(book);
em.getTransaction().commit();
} catch (Exception e) {
em.getTransaction().rollback();
throw e;
} finally {
em.close();
}
}
}
public class MyAppModule extends PrivateModule {
public static final String PROD_PERSISTENCE_UNIT_NAME = "prod";
#Override
protected void configure() {
initializePersistence();
}
private void initializePersistence() {
// persistence unit set to prod DB
final JpaPersistModule jpaPersistModule = new JpaPersistModule(PROD_PERSISTENCE_UNIT_NAME);
// connection properties set to suitable prod values
jpaPersistModule.properties(new Properties());
install(jpaPersistModule);
// expose bindings to entity manager annotated as "prod"
bind(JPAInitializer.class).asEagerSingleton();
bind(PersistService.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME)).to(PersistService.class).asEagerSingleton();
expose(PersistService.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME));
bind(EntityManagerFactory.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME)).toProvider(binder().getProvider(EntityManagerFactory.class));
expose(EntityManagerFactory.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME));
bind(EntityManager.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME)).toProvider(binder().getProvider(EntityManager.class));
expose(EntityManager.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME));
bind(UnitOfWork.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME)).toProvider(binder().getProvider(UnitOfWork.class));
expose(UnitOfWork.class).annotatedWith(named(PROD_PERSISTENCE_UNIT_NAME));
}
}
As a lesson, be very watchful around annotations and other such "magic" that modifies your code under the hood, finding bugs becomes quite difficult.
I have an injectable provider that may or may return null. I am getting an exception when it is null. I registered the provider as a Singleton, can I possibly register it as a type of SingletonContext that I customize to return true for supportsNullCreation()? I think if I can do that then even if findOrCreate() returns null, my code will still run which is what I want.
#ApplicationPath("rest")
public class MyApplication extends ResourceConfig
{
public MyApplication()
{
...
// Provider of DB
this.register( new AbstractBinder()
{
#Override
public void configure()
{
bindFactory(DbManager.class).to(EntityManagerFactory.class).in(Singleton.class);
}
});
}
Then it is used like this:
#Singleton
#Path("myservice")
public class WebServiceClass
{
// NOTE: Right now I have to comment this to run without a DB
#Inject
private EntityManagerFactory entityManagerFactory = null;
...
The exception I get is this...
java.lang.IllegalStateException: Context
org.jvnet.hk2.internal.SingletonContext#6cae5847 findOrCreate returned a null for
descriptor SystemDescriptor(
implementation=com.db.DbManager
contracts={javax.persistence.EntityManagerFactory}
scope=javax.inject.Singleton
qualifiers={}
descriptorType=PROVIDE_METHOD
descriptorVisibility=NORMAL
metadata=
rank=0
loader=org.glassfish.hk2.utilities.binding.AbstractBinder$2#7050f2b1
proxiable=null
proxyForSameScope=null
analysisName=null
id=145
locatorId=0
identityHashCode=863132354
reified=true)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2075)
...
I would recommend changing the design a bit. Using the EntityManagerFactory in the resource class is not very great design. You are left with code like
public class Resource {
private EntityManagerFctory emf;
#POST
public Response get(Entity e) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(e);
em.getTransaction().commit();
em.close();
}
}
There are a lot of things wrong with this picture. For one you are breaking the [Single Responsibility Principle][1]. Secondly this doesn't allow you to elegantly handle the null EMF, even if it was possible. You have this all over the place
if (emf != null) {
// do code above
} else {
// do something else.
}
Also it is no great for testing. The common pattern is to use a DAO layer. Personally I even add a service layer in between the DAO and the REST layer, but you can get away with just a DAO layer.
For example what I would do is create a common abstraction interface for the data access calls.
public interface DataService {
Data getData();
}
Then create an implementation for db access
public class WithDbService implements DataService {
private EntityManagerFactory emf;
public WithDbService(EntityManagerFactory emf) {
this.emf = emf;
}
#Override
public Data getData() {
...
}
}
Then create another implementation without db access.
public class WithoutDbService implements DataService {
#Override
public Data getData() {}
}
Then you can use a Factory to create the DataService. What you will do is use the ServiceLocator to try and find the EMF. If it is not null, return the WithDbService else return the WithoutDbService
public class DataServiceFatory implements Factory<DataService> {
private DataService dataService;
#Inject
public DataServiceFactory(ServiceLocator locator) {
// abbreviated for brevity
EMF emf = locator.getService(EMF.class);
if (emf != null) {
dataService = new WithDbService(emf);
} else {
dataService = new WithoutDbService();
}
}
#Override
public DataService provider() { return dataService; }
}
[...]
bindFactory(DataServiceFactory.class).to(DataService.class).in(..);
Then you can just inject DataService every where. As long as the two implementations follow the contract, it should work just fine.
There may be some design improvements, but it is a big step up from using the EMF directly in the resource class.
I'm using JPA and EJBs on WebSphere 7.
I have the following class:
#Entity
#Table(name="WIDGET")
public class Widget implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String details;
/* getters and setters */
}
I have a DAO like so:
#Stateless
public class WidgetDAO implements WidgetDAOLocal {
#PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
public EntityManager getEntityManager() {
if (emf == null) {
throw new Exception();
}
return emf.createEntityManager;
}
public Widget getWidget(Long id) {
Widget widget = null;
EntityManager em = getEntityManager();
try {
widget = (Widget)em.find(Widget.class, widgetId);
} finally {
em.close();
}
return widget;
}
public Widget createWidget(Widget widget) {
EntityManager em = getEntityManager();
try {
em.persist(widget);
em.flush();
} finally {
em.close();
}
return widget;
}
public Widget updateWidget(Widget widget) {
EntityManager em = getEntityManager();
try {
widget = getEntityManager().merge(widget);
em.flush();
} finally {
em.close();
}
return widget;
}
}
The create works fine and my widget appears in the database.
But when I try to do a merge, I get an error. The code to do the merge and the error I get follows:
public WidgetService {
#EJB
private WidgetDAO widgetDAO;
public WidgetDAO getWidgetDAO() {
return this.widgetDAO;
}
public Widget getWidget(Long id) {
return this.getWidgetDAO().getWidget(id);
}
public void updateDetails(Long widgetId, String details) {
Widget w = this.getWidget(widgetId);
w.setDetails(details);
this.widgetDAO.updateWidget(w);
}
}
The error is:
Exception caught from before_completion synchronization operation:
<openjpa-1.2.1-SNAPSHOT-r422266:686069 nonfatal user error> org.apache.openjpa.persistence.InvalidStateException:
The generated value processing detected an existing value assigned to this field: com.mydomain.domain.Widget.id.
This existing value was either provided via an initializer or by calling the setter method.
You either need to remove the #GeneratedValue annotation or modify the code to the initializer processing.
Any help on this is greatly appreciated!
Merge takes a copy of your entity, detaches it and persists the new one, which i presume attempts to set the ID from the old and causes you the conflict on your generated values. If you just want to update your object you should do so within a transaction and commit that.
Thanks for the help everybody, I figured it out, here's the cause of the problem and the solution that worked for me.
In my DAO I was doing this:
#Stateless
public class WidgetDAO implements WidgetDAOLocal {
#PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
public EntityManager getEntityManager() {
if (emf == null) {
throw new Exception();
}
return emf.createEntityManager;
}
Because the EntityManagerFactory was being injected via the #PersistenceUnit annotation, the entities were "Application-Managed", causing some kind of conflict with WebSphere.
I changed the code to this:
#Stateless
public class WidgetDAO implements WidgetDAOLocal {
#PersistenceContext
private EntityManager em;
public EntityManager getEntityManager() {
return em;
}
public Widget updateWidget(Widget widget) throws Exception {
return getEntityManager().merge(widget);
}
The #PersistenceContext annotation causes the entities to be "Container-Managed", and everything works now.
Thanks for the all the help and suggestions here. At the end of the day, I worked out the solution after re-focusing on the "Managing Entities" section of the documentation here:
http://docs.oracle.com/javaee/5/tutorial/doc/
I can't figure out what HibernateUtil is ...
Is it required with JPA?
I use JPA with GWT , is this implementation sufficient?
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public final class EMF {
private static final EntityManagerFactory emfInstance =
Persistence.createEntityManagerFactory("default");
private EMF() {}
public static EntityManagerFactory get() {
return emfInstance;
}
}
And at the use:
public class AccountDao {
public static final EntityManager entityManager() {
return Emf.get().createEntityManager();
}
public void createAccount(Account account) {
EntityManager em = entityManager();
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
em.persist(account);
tx.commit();
}
catch (Throwable t) {
t.printStackTrace();
tx.rollback();
}
finally {
em.close();
}
}
}
See this post (Gilead JPA configuration) please. I can't understand yet, how to use HibernateUtil, or HibernateJpaUtil, or PersistentBeanManager stuff ...
To use Gilead with GWT, first change your GWT-RPC service implementations from
public class MyServiceImpl extends RemoteServiceServlet implements MyService {
....
}
into:
public class MyServiceImpl extends PersistentRemoteService implements MyService {
....
}
Then, in the constructor of these classes, call the method setBeanManager(beanManager). Perform the setup as I described in my other answer. Here's the entire code snippet for reference:
public class MyServiceImpl extends PersistentRemoteService implements MyService {
public MyServiceImpl() {
EntityManagerFactory emf = EMF.get();
HibernateJpaUtil hibernateJpaUtil = new HibernateJpaUtil();
hibernateJpaUtil.setEntityManagerFactory(emf);
PersistentBeanManager persistentBeanManager =
GwtConfigurationHelper.initGwtStatelessBeanManager(hibernateJpaUtil);
setBeanManager(persistentBeanManager);
}
// Service methods follow here
}
This is sufficient for the setup - Gilead then uses the bean manager (and HibernateJpaUtils) automatically under the covers, you don't have to interact directly with it. All you have to do is to make sure, that your entities extend net.sf.gilead.pojo.gwt.LightEntity.
Your implementation is pretty sufficient. I would put the factory in the servlet context, rather than making it static though.
But note an important thing here. The above code will work if you are using it purely on the server-side.
Since you are using GWT, it is possible (although I don't think it is rational) to use hibernate "stuff" on the client-side. For that you'd need gilead, where you will need the forementioned utilities.
I want to create some sample code for JPA2 that can be run inside a Java EE container.
Running those sample normally require to have a Java EE server but i want to make things easier and to run them using an embedded container + maven.
Which one is better for this kind of "project" ?
Glassfish embedded , JBoss microcontainer or OPENEJB ?
Others ?
Thank you !
The problem to test EJB outside a container is that injections are not performed. I found this solution. In the stateless session bean you have an annotation #PersistenceContext
in a standalone Java-SE environment you need to inject the entitymanager by yourself, whcih can be done in an unittest. This is a fast alternative to an emmbeded server.
#Stateless
public class TestBean implements TestBusiness {
#PersistenceContext(unitName = "puTest")
EntityManager entityManager = null;
public List method() {
Query query = entityManager.createQuery("select t FROM Table t");
return query.getResultList();
}
}
The unittest instantiates the entitymanager and 'injects' it into the bean.
public class TestBeanJUnit {
static EntityManager em = null;
static EntityTransaction tx = null;
static TestBean tb = null;
static EntityManagerFactory emf = null;
#BeforeClass
public static void init() throws Exception {
emf = Persistence.createEntityManagerFactory("puTest");
}
#Before
public void setup() {
try {
em = emf.createEntityManager();
tx = em.getTransaction();
tx.begin();
tb = new TestBean();
Field field = TestBean.class.getDeclaredField("entityManager");
field.setAccessible(true);
field.set(tb, em);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#After
public void tearDown() throws Exception {
if (em != null) {
tx.commit();
em.close();
}
}
}