JPA base entity instantiate issue in dao layer when using #MappedSuperclass - java

I am aware that we could not instantiate abstract class, however the requirement that I have which requires to instantiate base entity class in dao layer and I am not sure which is most efficient way to resolve it.
Here is what I have in my base entity:
#MappedSuperClass
public abstract class User implements Serializable{
#Id
#Column(name = "USER_ID", unique = true, nullable = false)
private int userId
.......
Now I have two child entity which are pointed to two different tables which has identical columns
#Entity
#Table(name = "APP_ONE_USER")
public class AppOneUser extends User{
}
AND
#Entity
#Table(name = "APP_TWO_USER")
public class AppOneUser extends User{
}
My persistence.xml file looks like this
<persistence-unit name="APP_ONE_USER"
transaction-type="RESOURCE_LOCAL">
<class>com.mycom.entity.AppOneUser</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
<persistence-unit name="APP_TWO_USER"
transaction-type="RESOURCE_LOCAL">
<class>com.mycom.entity.AppTwoUser</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
I created two instances of entityManagerBean in my spring configuration for each persistence unit. At run time based on externalized property I am invoking entityManager with one or the other persistence unit
public class EntityManagerProvider {
#PersistenceContext(unitName="APP_ONE_USER")
private EntityManager em1;
#PersistenceContext(unitName="APP_TWO_USER")
private EntityManager em2;
public EntityManager getCurrentEntityManager(String persistenceUnitFlag){
if(persistenceUnitFlag.equalsIgnoreCase("appOne")){
return em1;
}
return em2;
}
}
In my DAO implementation
#Autowired
private EntityManagerProvider emProvider;
private #Value("${persistence.unit.flag}") String persistenceUnitFlag;
#PostConstruct
private void EntityManagerProvider(){
this.manager = emProvider.getCurrentEntityManager(persistenceUnitFlag);
}
Now In my service implementation I have to instantiate this User base entity to set values (because I have to retrieve fields from incoming request) while instantiating
Because base entity is abstract I can not instantiate.
If I remove abstract from the base class no compilation error but while saving object I am getting unknown entity error
My DAO method looks like this
public void saveUser(User user) {
manager.persist(user);
}

Related

How to persist when using Spring Boot with JPA

I'm used to using Spring Roo to generate my entities and having it handle injecting the entityManager as well as the persist and other methods via AspectJ classes.
Now I'm trying to use Spring Boot to do something simple that will write things to the database ...
#Entity
#Table(name = "account")
public class Account {
transient EntityManager entityManager;
#Id
#GeneratedValue
private Long id;
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "password", nullable = false)
private String password;
... getters and setters
#Transactional
public void persist() {
if (this.entityManager == null) this.entityManager = entityManager();
this.entityManager.persist(this);
}
#Transactional
public Account merge() {
if (this.entityManager == null) this.entityManager = entityManager();
Account merged = this.entityManager.merge(this);
this.entityManager.flush();
return merged;
}
When I'm calling persist or merge, entityManager is obviously null.
I've also tried adding implements CrudRepository<Account, Long> to the Account class to see it'll give me that functionality via a Default Implementation, but what I'm getting is simply empty classes that needs to be filled in.
I've had a look at the Spring Boot docs, they cover it very briefly omitting just enough detail to so that it's not obvious what I'm missing.
I have an Application class that bootstraps the application:
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
My properties file looks like this:
spring.application.name: Test Application
spring.datasource.url: jdbc:mysql://localhost/test
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
This database is automatically being created thanks to the ddl-auto=update property
What is the correct way to persist entities in Spring Boot + JPA and if what I've done is correct so far, how do I "autowire" or auto-create the entityManager?
In your example your EntityManager is always going to be null. Spring will not automatically wire one into your Entity class. I'm also not sure what your goal is here but I'm willing to bet you most likely don't want to have your Entity hold your EntityManager
I think what you may be looking for are Spring Data Repositories. I would recommend reading that to get the basics.
To get started with repositories:
First thing I would do would be remove transient EntityManager entityManager; and your persist/merge functions from your Account class.
Inside of your Application class you can add the #EnableJpaRepositories annotation.
Next create a new Interface (not a new class), this will be your Account repository.
#Repository
public interface AccountRepository extends PagingAndSortingRepository<Account, Long>
Where Account is the type of Entity and Long is the ID type of Account
There are a few repository interfaces with various support included with Spring Data that inherit from Repository.
Without adding anything to your interface, PagingAndSortingRepository will give you support CRUD operations and paging.
Its also possible to add custom queries to your interface using JPQL, take a look at the #Query annotation. http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query
Now, you can #Autowire AccountRepository into any of your Spring managed beans and begin saving and fetching data.
Try replacing:
#Configuration
#ComponentScan
#EnableAutoConfiguration
with:
#SpringBootApplication
See this article
Specifically: By default, Spring Boot will enable JPA repository support and look in the package (and its subpackages) where #SpringBootApplication is located. If your configuration has JPA repository interface definitions located in a package not visible, you can point out alternate packages using #EnableJpaRepositories and its type-safe basePackageClasses=MyRepository.class parameter.
the problem in your code was:
EntityManager entry was not #Autowired and even if it was #Entity isn't recognized as a spring bean and for this reason the dependency injection service of spring didn't work
since that how i said previously the bean annotated with #Entity isn't a spring bean and for this reason you can't benefit of #Transactional annotation
You can use Spring DataJPA project in this case remember of configure tis with #EnableJpaRepositories or you can create the your repository organizing your code in this way
Entity:
#Entity
#Table(name = "account")
public class Account {
#Id
#GeneratedValue
private Long id;
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "password", nullable = false)
private String password;
....
}
Repository layer:
public interface AccountRepository {
void persist();
Account merge();
}
#Repository
class AccountRepositoryJpaImpl implements AccountRepository {
#Autowired
private EntityManager entityManager;
...
#Transactional
public void persist() {
if (this.entityManager == null) this.entityManager = entityManager();
this.entityManager.persist(this);
}
#Transactional
public Account merge() {
if (this.entityManager == null) this.entityManager = entityManager();
Account merged = this.entityManager.merge(this);
this.entityManager.flush();
return merged;
}
....
}
#SpringBootApplication for benefit of all feature of spring boot
#EnableTransactionManagement for benefit of Transaction management
#SpringBootApplication
#EnableTransactionManagement
class ApplicationConfig {
public static void main(String[] args) {
SpringApplication.run(ApplicationConfig .class, args);
}
}
I hope that this can help you. (Spelling corrected 2018-02-24)

Why am I getting a TransactionRequiredException in #PostConstruct method in JTA EJB?

I have Java EE project where I want to use an injected JTA EntityManager in the #PostConstruct method. EntityManager.persist fails due to javax.persistence.TransactionRequiredException. It succeeds when called through an EJB instance injected into a JSF managed bean. Manually starting a transaction with #Resource UserTransaction and UserTransaction.begin/commit or EntityManager.getTransaction.begin/commit because it's a JTA EntityManager.
The EJB interface
#Local
public interface UserService extends Serializable {
public void saveUser(AUser user);
}
#Entity
public class AUser implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id;
private String username;
public AUser() {
}
public AUser(String username) {
this.username = username;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
The EJB implementation:
#Stateless
public class DefaultUserService implements UserService {
private static final long serialVersionUID = 1L;
#PersistenceContext
private EntityManager entityManager;
public DefaultUserService() {
}
#PostConstruct
private void init() {
AUser user = new AUser("initUser");
saveUser(user);
}
#Override
public void saveUser(AUser user) {
entityManager.persist(user);
}
}
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="richtercloud_javaee-persist-in-postconstruct-jar_jar_1.0-SNAPSHOTPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/example1</jta-data-source>
<class>richtercloud.javaee.persist.in.postconstruct.jar.entities.AUser</class>
<properties>
<property name="eclipselink.target-database" value="Derby"/>
<!-- necessary in order to avoid syntax errors -->
<property name="javax.persistence.schema-generation.database.action" value="create"/>
<property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
<property name="eclipselink.target-server" value="Glassfish"/>
<!-- avoid non-severe NullPointerException being logged in GlasFish
<ref>https://java.net/jira/browse/GLASSFISH-21468f</ref>-->
</properties>
</persistence-unit>
</persistence>
I didn't know how to provide the jdbc/example1 data source (it's GlassFish 4.1 JDBC resource based on a JDBC connection pool referring to a Derby database with network driver). Everything else it available at https://github.com/krichter722/javaee-persist-in-postconstruct.
I read Persisting in #PostConstruct: javax.persistence.TransactionRequiredException which exceeds the example of a simple EntityManager.persist call in #PostConstruct and http://www.tikalk.com/java/doing-transactional-work-spring-service-using-postconstruct-method/ which refers to Spring which I'm not using. I found no statement that #PersistenceContext EntityManager behaves differently in #PostConstruct.
§8.6.2 of the EJB 3.2 specification states:
The term “an unspecified transaction context” is used in the EJB specification to refer to the cases in which the EJB architecture does not fully define the transaction semantics of an enterprise bean method execution.
This includes the following cases:
...
• The execution of a PostConstruct or PreDestroy callback method of a stateless session bean with container-managed transaction demarcation.
An alternative solution may be to specify the javax.persistence.sql-load-script-source property in your persistence.xml file. It points at a SQL script that will preload your database. This can be a resource embedded in your application or a file URL.
it doesn't guarantee that #PostConstruct and #PreDestroy are a part of transaction. so no DB operations should be done in PostConstruct method as well as PreDestroy method.

It takes half a second to persist an entity (JPA/Hibernate)

I'm not very experienced with hibernate, but this seems way too much.
When I'm trying to persist a very simple entity, such as this:
#Entity
public class SomeEntity {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
String somePropery;
public String getSomePropery() {
return somePropery;
}
public void setSomePropery(String somePropery) {
this.somePropery = somePropery;
}
}
It takes 0.7 seconds.
Am I right that it should be way less? If so, what is the reason?
This is my configuration:
spring.dataSource.driver-class-name=com.mysql.jdbc.Driver
spring.dataSource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.max-active=5
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true
Update:
I use spring data JPA, and this is the test that runs:
#Test
public void test(){
SomeEntity entity = new SomeEntity();
someEntityRepository.save(entity);
}
someEntityRepository is a JpaRepository.

Use #RequestScoped and #Produces to Inject User Entity into the Jersey handler

User Entity class:
#Entity
public class User implements Serializable {
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
public List<Site> sites;
Facade class to access database:
#Stateless
public class UserFacade extends AbstractFacade<User, Long> {
#PersistenceContext
private EntityManager em;
...
}
Resource class for User injection:
#RequestScoped
public class Resource {
#Inject
UserFacade userFacade;
#Inject
HttpServletRequest request;
#Produces
public User getUser() {
final String name = request.getUserPrincipal().getName();
// ... find user in database ...
}
}
And Jersey handler:
#Stateless
#Path("/sites")
public class Sites {
#EJB
SiteFacade siteFacade;
#Inject
User user;
...
Here is the problem now:
When I want to access user.sites list, I'm getting lazy load exception. But apparently because User injected by RequestScoped provider, it should refresh per request with same EntityManager session. Right?
Is there anyway I inject User Entity per rest request into Rest handler class?
The EntityManager is bound to the transaction, not to the request scope.
So the User producer method and your Sites business method are called in two distinct transactions, which explains the LazyLoadException.

Hibernate #Version annotation

What is the relation between hibernate #version and ManyToOne Mapping.
Assume that i am having two tables Department and Employee. Here is Deparment is the master table
and Employee in the detail table. In the Employee table, departmentID is reference as foreign key.
Here is my classes
Public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long ID;
#Version
private Long version;
//Getters and Setters
}
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long ID;
#Version
private Long version;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "departmentID" )
private Department department;
}
And also, Spring handles the session. So assume that, in one page, particular department is fetched and stored
in the HTTP session.
Now in another page, i am trying to do the following
Employee emp = new Employee();
emp.setName('Test')
emp.setDepartment(dept) // already stored in the HTTP session variable
service.save(emp)
Now i am getting the following exception
org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance - save the transient instance before flushing:
And just it make one change as follow and there is errror
Employee emp = new Employee();
emp.setName('Test')
dept.setVersion(0);
emp.setDepartment(dept) // already stored in the HTTP session variable
service.save(emp)
My Spring config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Container Configuration: The IOC container configuration xml file is
shown below,The container has the <context:component-scan> element and <context:annotation-config/>
<context:annotation-config/> used to intimate the beans of this IOC container
are annotation supported. By pass the base path of the beans as the value
of the base-package attribute of context:component-scan element, we can detect
the beans and registering their bean definitions automatically without lots
of overhead. The value of base-package attribute is fully qualified package
name of the bean classes. We can pass more than one package names by comma
separated -->
<context:annotation-config />
<context:component-scan base-package="com.product.business" />
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- This will ensure that hibernate or jpa exceptions are automatically
translated into Spring's generic DataAccessException hierarchy for those
classes annotated with Repository -->
<bean
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="CRUDService" class="com.product.business.service.CRUDServiceImpl" />
<bean id="AuthService" class="com.product.business.service.AuthServiceImpl" />
Service Implementation
package com.product.business.service;
import java.io.Serializable;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.product.business.dao.CRUDDao;
#Service
public class CRUDServiceImpl implements CRUDService {
#Autowired
private CRUDDao CRUDDao;
#Transactional(readOnly = true)
public <T> List<T> getAll(Class<T> klass) {
return CRUDDao.getAll(klass);
}
#Transactional
public <T> void Save(T klass) throws DataAccessException {
CRUDDao.Save(klass);
}
#Transactional
public <T> void delete(T klass) throws DataAccessException {
CRUDDao.delete(klass);
}
#Transactional
public <T> T GetUniqueEntityByNamedQuery(String query, Object... params) {
return CRUDDao.GetUniqueEntityByNamedQuery(query, params);
}
#Transactional
public <T> List<T> GetListByNamedQuery(String query, Object... params) {
return CRUDDao.GetListByNamedQuery(query, params);
}
#Override
#Transactional(readOnly = true)
public <T> Long getQueryCount(String query, Object... params) {
return CRUDDao.getQueryCount(query, params);
}
#Override
#Transactional(readOnly = true)
public <T> T findByPrimaryKey(Class<T> klass, Serializable id) {
return CRUDDao.findByPrimaryKey(klass, id);
}
}
You need to first save the Department before saving the Employee.
service.save(dept);
service.save(emp);
UPDATE in response to your comment:
In order to associate an Employee with a Department you need to have a Department that exists. Remember that in your database the Employee has a FK to the Department so what Hibernate is complaining about is that you are trying to save an Employee with a Department that does not exist, so you have these options:
If the Department is a new Department you must save it first before saving the Employee.
Find an already stored Department through a query such as entityManager.find(id, Department.class) and use that object in your Employee object.
Mark as #Cascade your relationship with Deparment in the Employee.
Your main problem is not so much the cascading but the fetching.
see the following post:
Difference between FetchType LAZY and EAGER in Java Persistence API?
#ManyToOne(fetch = FetchType.EAGER)
Otherwise as you mentionned your session gets closed and you loose the object. Eager fetching will ensure that it stays opened
I know this is an old post, but maybe this will help others.
This assumes you are using Hibernate as a JPA implementation.
Since your Department is stored in the session it's safe to say that it is detached.
The best route for this case, since you are not modifying the Department instance is this:
Employee emp = new Employee();
emp.setName("Test");
emp.setDepartment(em.getReference(Department.class, dept.getID());
service.save(emp);
See Hibernate documentation here: Entity Manager - Loading an Object
If you get an EntityNotFoundException, make sure the code that originally retrieves Department calls at least one method on it within the transaction in which it is retrieved.

Resources