I am currently facing a weird issue with a plain Java EE application on WildFly 25 for which I don't find the root cause. I've been using similar configurations for a few customers and never had any issue with the code. I know for transactions to work, I need to inject everything involved properly, use the #Stateless annotation and work with the #Transactional annotation on methods which need it. But I never had the issue that I just don't get any transaction, and I am somewhat lost right now. The datasource was also configured with JTA set to true.
My repository:
#Stateless
public class DocumentImportLogRepository{
#PersistenceContext(unitName = "AktenimportPU")
EntityManager em;
public <T> Object find(Class<T> entityClass, Object primaryKey)
{
return em.find(entityClass, primaryKey);
}
public void persist(Object object)
{
em.persist(object);
}
public void forcePersist(Object object)
{
em.persist(object);
em.flush();
}
public void merge(Object object)
{
em.merge(object);
}
public void forceMerge(Object object)
{
em.merge(object);
em.flush();
}
public void remove(Object object)
{
em.remove(object);
}
is called within the following service class:
#Stateless
public class DocumentImportService
[...]
#Inject
DocumentImportLogRepository importLogRepo;
from several methods all originating from:
#Transactional
public void doImport()
{
[...]
readInputFolder(Config.DOCUMENT_IMPORT_FOLDER);
prepareImport(importLogRepo.getByState(State.PARSED), getPersonalakten());
performArchive(importLogRepo.getByState(State.PREPARED));
performArchiveMove(importLogRepo.getByState(State.ARCHIVED));
[...]
}
which is triggered by a controller:
#Named("StartController")
#ApplicationScoped
public class StartController implements Serializable {
#Inject
private transient DocumentImportService importService;
[...]
#Transactional
#TransactionTimeout(value=120, unit = TimeUnit.MINUTES)
public void performTask(Task task)
{
[...]
switch(task)
{
case Personalaktenimport:
importService.doImport();
break;
}
[...]
}
the actual method call failing:
#Transactional
public void readInputFolder(Path inputFolder) throws IOException
{
[...] importLogRepo.forcePersist(entry); [...]
}
with the exception:
javax.ejb.EJBTransactionRolledbackException: WFLYJPA0060: Transaction is required to perform this operation (either use a transaction or extended persistence context
persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="AktenimportPU">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:jboss/datasources/Aktenimport</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="none"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.jdbc.time_zone" value="Europe/Berlin"/>
</properties>
</persistence-unit>
</persistence>
I finally found out what caused this error:
I wasn't really reading the exceptions prior since I thought that they are just commonly caught mistakes in the inputs, but yeah, I had several exceptions caught, however, javax.validation.ValidationException wasn't one of them. The mistake was that the entity had a field BARCODE whose type was an enumeration BARCODE_TYPE which contains a set of predefined values. My intention was to just let it run into an error but continue the import on unknown types, however, if this exception appears it seems to set the transaction into an error state from which the application cannot recover. Removing the #NotNull annotation on the enum field did get rid of the errors.
Related
I've a war file which runs on a wildfly application server.
When I do a SOAP request, a servor log error occurs saying that my EJB session is null. Here's my code :
ColisDAO.java
#Stateless
#LocalBean
public class ColisDao {
public static final String SELECT_ALL_COLIS = "select * from Colis;";
#PersistenceContext(unitName="bdd_colis")
private EntityManager em;
public ColisDao() {
}
public void creer(Colis colis) {
...
}
public void remove(Colis colis) {
...
}
}
RecoveryImpl.java
public class RecoveryImpl {
#EJB
private static ColisDao colisDao;
public static void fillDataBase() throws IOException {
...
some code
...
colisDao.creer(c); //here's my error NullPointer
}
}
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="bdd_colis" transaction-type="JTA">
<jta-data-source>java:/bdd_colis</jta-data-source>
<class>data.Colis</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
</properties>
</persistence-unit>
</persistence>
I dont really understand where I've wrong, maybe I have to create ejb file and use InitialContext.lookup() function but I don't really know how to use it in my context.
Any suggestions ?
UPDATE
Finally found the solution :
Here's my new RecoveryImpl class :
RecoveryImpl.java
#EJB(name="ejb/colisDao", beanInterface=ColisDao.class)
public class RecoveryImpl {
public static void fillDataBase() throws IOException {
try {
colisDao = (ColisDao) new InitialContext().lookup("ejb/colisDao");
}
colisDao.creer(c);
}
}
RecoveryImpl class is not a bean, so ColisDao bean won't be injected. Only if class is a bean(specified using annotations like #Stateless #LocalBean), beans get injected.
If class isn't bean and still you want to bean in that class,(hereRecoveryImpl class): Way to access it is using
lookup method of Context
I'm running JUnit tests using spring-test, my code looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {})
#Transactional (propagation = Propagation.REQUIRED)
#Rollback
public class MyTest {
#Autowired
private MyRepository repository;
#Before
public void before() {
//clean repository
}
#Test
public void test_1() {
//add new entity
}
#Test
public void test_2() {
//add new entity
}
...
}
I want to rollback my db in state before all tests. And tables rollbacks but sequence for id generation increases with each test.
Please help me to find the way to set sequence in start value before each test.
I'm using Spring, Hibernate, HsqlDb
If you call a method with #Transactional you can't make a rollback. What you can do is an #After in order to drop all the database, and in a #Before create it again. I think it's not a very good idea, you should drop the values in order to isolate each test. I recommend you to use H2 database in order to be able to use in memory storage, so you don't have to worry about the id number.
You have to add this dependency to the pom:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.193</version>
</dependency>
And the configuration inside the .xml should be something like this:
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">org.h2.Driver</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.connection.url">jdbc:h2:mem:testDB;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1</property>
<property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
<property name="show_sql">false</property>
<property name="hbm2ddl.auto">create</property>
</session-factory>
</hibernate-configuration>
Of course you should adapt it to your system, but you must keep that username and password in order to connect successfully.
If you don't want to auto create the tables, you could add this parameter on the connection URL:
INIT=RUNSCRIPT FROM 'classpath:scripts/create.sql
and this will run your script before the tests.
Then in your tests you could do something link this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {})
#Transactional (propagation = Propagation.REQUIRED)
public class MyTest {
#Autowired
private MyRepository repository;
#Test
public void test_1() {
//add new entity
}
#Test
public void test_2() {
//add new entity
}
#After
public void tearDown(){
repository.clean();
}
}
And the clean method could be something like this
public void clean(){
for (T obj: this.findall()) //replacing T for the type if you don't use generics
session.delete(obj); //your entity manager or session, depending on how you do the queries
}
I need to inject EntityManager in EntityListener class so that I can perform CRUD operation on it.
POJO:
#Entity
#EntityListner(AuditLogging.class)
class User
{
//Getter / setter of properties
}
AuditLogging (Listner class)
public class AuditInterceptor
{
#PersistenceContext
EntityManager entityManager;
public void setEntityManager(EntityManager entityManager)
{
this.entityManager = entityManager;
}
#PrePersist
public void prePersist(Object obj)
{
// Here I want to use ENTITY manager object so that I can perform CRUD operation
// with prePersist coming object.
entityManager.unwrap(Session.class).save(obj);
// But I am getting NULL POINTER EXCEPTION for entity manager object
}
}
JDBC-CONFIg.xml
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="packagesToScan" value="com.XXXXX.entity" />
<property name="jpaProperties">
</bean>
<!-- Datasource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driver.classname}" />
<property name="jdbcUrl" value="${jdbc.url}" />
</bean>
<!-- transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
EntityListener is not managed by any of the container.EntityListeners are instanciated by JPA, so Spring does not have an opportunity to inject EntityManager.
My question is, how we can inject inject EntityManager in EntityListener class so that I can perform CRUD operation on it ???
I have faced a similar problem where I was trying to create history records for an entity using EntityListeners.
In order to resolve this problem, I have created utility class BeanUtil with a static method to get the bean and used this util class to get bean inside my Entitylistener class
#Service
public class BeanUtil implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
Now we can call BeanUtil.getBean() to get the bean of any type
public class FileEntityListener {
#PrePersist
public void prePersist(File target) {
perform(target, INSERTED);
}
#Transactional(MANDATORY)
private void perform(File target, Action action) {
EntityManager entityManager = BeanUtil.getBean(EntityManager.class);
entityManager.persist(new FileHistory(target, action));
}
}
We can use this BeanUtil class to get any spring managed bean from anywhere, To know more you can read my article JPA Auditing: Persisting Audit Logs Automatically using EntityListeners.
Anyways, I got this done by getting entityManager reference from EntityManagerFactory bean which is configured in my jdbc-config.xml. But again this is not what I wanted. I wanted to work around with #PersistenceContext.
#Autowired
EntityManagerFactory entityManagerFactory;
private static EntityManager entityManager;
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
entityManager=entityManagerFactory.createEntityManager();
this.entityManagerFactory = entityManagerFactory;
}
Here are few notes that we need to keep in mind:
We can't inject an EntityManager into an EntityListener (through
#PersistenceContext). EntityListener is not managed by any of the
containers
#PersistenceContext class cannot be static. So we cant
attain the instance while class loading.
EntityListeners are
instantiated by JPA, so Spring does not have an opportunity to
inject EntityManager
Well, the first solution which came into my mind is a little "hack", but should work.
public class AuditInterceptor {
static setEntityManager emf;
#Autowired
public void setEntityManagerFactory(EntityManager emf) {
AuditInterceptor.emf = emf;
}
#PrePersist
public void prePersist(Object obj) {
EntityManager entityManager = emf.getEntityManager();
// Here I want to use ENTITY manager object so that I can perform CRUD operation
// with prePersist coming object.
entityManager.unwrap(Session.class).save(obj);
// But I am getting NULL POINTER EXCEPTION for entity manager object
}
}
Inside of your code use EntityManager entityManager = emf.getEntityManager()
Declare your AuditInterceptor as a spring bean (#Component with component-scan or define AuditorInterceptor as a bean)
I used a ThreadLocal to pass the Spring Application Context which contains EntityManager around. Though I am not sure if it is safe Is it safe to pass in the Spring Application Context into a ThreadLocal associated with a request? but so far it is working for me.
The listener can be modified to have autowiring like this. However this needs to be done on on the handlers and not the constructor (doing it on the constructor seems less predictable). You are also not limited to the EntityManager but you have access to the whole context.
#Autowired
private EntityManager entityManager;
#Autowired
private MyDao myDao;
#PrePersist
public void pre() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
Objects.requireNotNull(myDao);
myDao.doSomething();
}
I am injecting dependency in one class. But not finding when I call method of that class.
public StudentValidator extends MyValidator implements Validator{
private StudentRepository studentRepository;
//setter for the same
public void validate(Object obj,Errors errors){
validateStudent(Obj)
}
}
public class MyValidator{
private StudentRepository studentRep;
public void setStudentRep(StudentRepository studentRep){
System.out.println("This is printing on Tomcat console");
this.studentRep=studentRep
System.out.println("This is also printing"+studentRep+" with hashcode");
}
public void validateStudent(Object obj){
studentRep.findStud(); getting here NullPointerException
}
}
No need of writing Spring servlet as I can see dependency has been injected in setters through Syso statements.
What would be problem for the same?
UPDATE
spring-servlet.xml
<beans>
<bean id="studentValidator" class="SyudentValidator" >
<property name="studentRepository" ref="studentRepository">
</bean>
<bean id="myValidator" class="MyValidator">
<property name="studentRep" ref="studentRepository">
</bean>
<bean id="studentRepository" class="StudentRepository">
</beans>
NullPointerException is not my problem. Problem is why I am getting the null pointer in this case as Syso statement is printing my dependencies hashcode.
Assuming both MyValidator and StudentValidator are spring beans, you should try:
bean id="myValidator" class="MyValidator.java">
bean id="studentValidator" class="StudentValidator.java" parent="myValidator>
You must notify spring that there is an inheritance.
You have declared a field of type StudentRepository twice, which is confusing but here's what I think is going on.
I assume you are creating an instance of StudentValidator, which will set the field StudentValidator.studentRepository. However your validateStudent method uses the field MyValidator.studentRep that will remain null, hence the NullPointerException.
Basically, only methods can be overridden in Java, not fields.
If you really need this unnecessary inheritance structure, the code should read:
public class MyValidator
{
private StudentRepository studentRepository;
public void setStudentRepository(StudentRepository studentRepository)
{
this.studentRepository = studentRepository;
}
public void validateStudent(Object obj)
{
studentRepository.findStud();
}
}
public StudentValidator extends MyValidator implements Validator
{
#Override
public void validate(Object obj, Errors errors)
{
validateStudent(Obj)
}
}
Though I'd be tempted to simplify it to:
public class StudentValidator implements Validator
{
private StudentRepository studentRepository;
public void setStudentRepository(StudentRepository studentRepository)
{
this.studentRepository = studentRepository;
}
#Override
public void validate(Object obj)
{
studentRepository.findStud();
}
}
UPDATE
Based on the Spring configuration above, I can see you are creating instances of both classes - not sure why you'd do that if you're not going to use the myValidator bean as a parent of the studentValidator bean, but either way, if you've only got one bean, using a parent just complicates the Spring configuration of no reason.
The reason you're getting a NullPointerException in the validateStudent is because you never set the studentRep on the studentValidator bean, you only set it on the myValidator bean (they're two different instances).
Given this, you're Spring config should read:
<beans>
<bean id="studentValidator" class="SyudentValidator" >
<property name="studentRepository" ref="studentRepository">
<property name="studentRep" ref="studentRepository">
</bean>
<bean id="studentRepository" class="StudentRepository">
Though as I said, your class design is confusing in the first place, which makes this Spring config look weird as you're setting a reference to the same bean, studentRepository, twice.
My advice would be to apply the class changes I originally suggested, which simply the design as a whole and make it harder to misconfigure you application as is currently happening.
I understand we need to keep #Transactional boundaries as short as possible. Here is the code :
I am using userDAO object through Spring dependency injection :
private static ApplicationContext context ;
private UserDAO userDAO;
public TransactionsTest() {
userDAO = (UserDAO) context.getBean("userDAO");
}
I am calling testSaveUserAccounts() from TransactionsTest class trying to use userDAO for insertion/updation of data.
Case 1:
#Transactional
public void testSaveUserAccounts() {
UserAccounts userAccounts = new UserAccounts();
userAccounts.setCommunityId(10L);
userDAO.saveObject(userAccounts);
}
// This method is inside UserDAO
public void saveObject(Object object) {
entityManager.merge(object);
}
Case 2:
#Transactional
public void testSaveUserAccounts() {
UserAccounts userAccounts = new UserAccounts();
userAccounts.setCommunityId(10L);
userDAO.saveObject(userAccounts);
}
// This method is inside UserDAO
#Transactional(propagation=Propagation.REQUIRED)
public void saveObject(Object object) {
entityManager.merge(object);
}
Spring Context :
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceLocal" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceUnitName" value="spring-jpa" />
</bean>
UserDAO :
#Repository
public class UserDAO extends BaseDAO {
#Transactional(propagation=Propagation.REQUIRED)
public void saveObject(Object object) {
entityManager.merge(object);
}
}
BaseDAO :
public abstract class BaseDAO {
protected EntityManager entityManager;
protected HashMap<String,Long> eventIdMap = new HashMap<String,Long>();
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this. entityManager = entityManager;
}
public <T> T getById(final Class<T> clazz, final Serializable id) {
T object = clazz.cast(entityManager.find(clazz, id));
return object;
}
#Transactional
public Object save(Object ob) {
Object object = entityManager.merge(ob);
return object;
}
#Transactional
public void persist(Object ob) {
entityManager.persist(ob);
}
#SuppressWarnings("unchecked")
public <T> ArrayList<T> getAll(final Class<T> clazz) {
String hqlQuery = "from "+ clazz.getSimpleName();
ArrayList<T> list = (ArrayList<T>)entityManager.createQuery(hqlQuery).getResultList();
return list;
}
}
I have been experimenting around several transactional boundaries REQUIRED, REQUIRES_NEW, SUPPORTS, etc but couldn't confidently make out as to why Case 1 (when method2 is called which is inside transactional boundary of method1) does not merges the data, while, this is solved in Case 2.
Why do I need to specify #Transactional in inner methods as well when already I have marked calling function within Transaction boundary ?
Your transaction test class is not a Spring Bean that is why Case 1 does not work. Spring needs to detected that a method has #Transactional on it and it does that when spring registers the bean with the spring bean factory.
Also keep in mind that the if you are doing Proxy Based AOP calls within the same bean will not be caught by the transaction aspect unless you use AspectJ load time weaving or AspectJ compile time weaving.
Also putting #Transactional on your Dao's is not a really a good idea because transaction boundaries are best marked at the service layer. The reason why is that a particular service method might need to interact with multiple Dao's and you would want those Dao's actions to be part of the tx started by the service layer, rather than having to analyze the Dao's to see what the propagation behavior is.
Can you post the complete code for the test class?
#Transactional does nothing locally, it only has an effect when called from a different service. In other words, you have to leave your current context for transaction annotations to do anything. so calling method 1 is identical in both cases, Case 2 only does anything if method2 is called from another service.