Saturday, May 16, 2020

JPA entity removal fails silently


>PROBLEM


The JPA remove command was silently ignored.
There was no delete statement on server's output even though the show_sql was enabled:
 
<property name="hibernate.show_sql" value="true"></property>
 
 
The issue was around an OneToMany relation where:
todo 1 --- * todoitem
 

Attempt to delete an instance on any side fails silently, without having the respective "delete" command on the server's output and no exception message of any type.

 

>SOLUTION

 
First, I switched the many side's code suggested by the Wildfly18/JBoss documentation in its examples from:
 
//    @Override
//    public void delete(Todoitem todoitem) {
//        if (todoitem == null) {
//            return;
//        }
//        if (!emPg.contains(todoitem)) {
//            todoitem = emPg.merge(todoitem);
//        }
//        emPg.remove(todoitem);
//        emPg.flush();
//        emPg.clear();
//    }
    

To an equivalent form:
 
    @Override
    public void delete(Todoitem todoitem) {
        if (todoitem == null) {
            return;
        }
        Todoitem ti = emPg.find(Todoitem.class, todoitem.getId());
        if(ti == null) {
            return;
        }
        emPg.remove(ti);
        emPg.flush();
        emPg.clear();
    }
 

Unfortunately, I got the same result - removal silently ignored.
 

Then, I suspected of the database, since hibernate handles its own keys. I had done many tests during implementation...
To be sure about the consistency issues, I've decided to empty the database deleting the content of both sides of the relation.
Then I created new entity instances and relations using the application's resources (no SQL command) since everything was working well except for entity removal.
After, I checked the database relations using SQL command to make sure everything was fine, and it was.
 
Next, I tried a new test again but this time it was successful.

Then I reverted the code, uncommenting the commented code and vice-versa and tested again.
The test failed again, returning same result — silently ignoring remove.

I set back the code to the previous condition testing again to confirm results.
The confirmations was successful, confirming suspicion of two issues, database and code implementation.
 
Since good news, I repeated the same to the "One" side (code below - the commented code is the initial one inherited from Wildfly 18 documentation, as above mentioned). 
 
From:
//    @Override
//    public void delete(Todo todo) {
//        if(todo == null) {
//            return;
//        }
//        if (!emPg.contains(todo)) {
//            todo = emPg.merge(todo);
//        }
//        //todoitemDao.deleteAll(todo);
//        emPg.remove(todo);
//        emPg.flush();
//    }
 
 
To:
    
    @Override
    public void delete(Todo todo) {
        if (todo == null) {
            return;
        }
        Todo t = emPg.find(Todo.class, todo.getId());
        if(t == null) {
            return;
        }
        emPg.remove(t);
        emPg.flush();
        emPg.clear();
    }
 

 
Issue solved. Success.
 

IMPORTANT NOTE:
 
Check the removal tests by using the SQL statements straight on the database.
Sometimes the instance seems not being removed due to cache issue or code implementation fault, requiring to be treated apart.


>ENV


- JSF
- Wildfly 18 (JPA default implementation - Hibernate)
- PostgreSQL 10


>NOTE

Published also on Stackoverflow

Wednesday, May 6, 2020

WILDFLY/JBOSS: WFLYJPA0061: Persistence unitName was not specified and multiple persistence unit definitions


  

>PROBLEM

Creating a persistence.xml file having two persistence units caused the following Wildfly's error message:

Caused by: java.lang.IllegalArgumentException: WFLYJPA0061: Persistence unitName was not specified and there are 2 persistence unit definitions in application deployment deployment "todos.war". Either change the application deployment to have only one persistence unit definition or specify the unitName for each reference to a persistence unit.

The persistence.xml configuration used was:


<?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="primary">
       <jta-data-source>java:jboss/datasources/TasksJsfQuickstartDS</jta-data-source>
       <properties>
          <!-- Properties for Hibernate -->
          <property name="hibernate.hbm2ddl.auto" value="create-drop" />
          <property name="hibernate.show_sql" value="false" />
       </properties>
    </persistence-unit>

    <persistence-unit name="pgTestoneDS">
       <jta-data-source>java:jboss/datasources/pgTestoneDS</jta-data-source>
       <properties>
<!--           <property name="hibernate.hbm2ddl.auto" value="create-drop" /> -->
<!--           <property name="hibernate.show_sql" value="false" /> -->
       </properties>
    </persistence-unit>

</persistence>

 

>SOLUTION

After some failures, I've decided to repeat the same configuration but doing the things in a different order.
The following order was successful:

1. Refactor the code that concerns the primary persistent-unit (or the the initial persistent-unit, whatever the name it has).

2. Create a qualifier to this first perstent-unit.

3. Refactor the dao layer in order to apply the its qualifier where the entity maneger is injected.

4. Recompile the project and perfome a full deploy.

5. Start the server and test.

6. Stop the server

7. If not successful, fix the code revising from step 1.

8. if successful, add the second persistent-unit to persistence.xml file.

9. Create the  database manager class, its qualifier, the entities and dao layer always using the respective qualifier for the second persistent-unit to differ from the initial code implemented for the first persistent-unit.

10. Recompile the project and perfome a full deploy.

11. Start the server and test.





Source code available at the link below.


>WHAT NOT TO DO

This site is dedicated to provide straight problem/solution approach, but sometimes it is valuable to lean from the mistakes but this kind of approach doesn't fit here.
To get more details and source code, point to WILDFLY/JBOSS: WFLYJPA0061: Persistence unitName was not specified and double persistence unit definitions



>ENV

Windows 10
Wildfly 18
JEE/CDI/JPA

 

eclipse: java: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder" or Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder

  >PROBLEM Using Eclipse, you try to run a simple logging test using "org.slf4j.Logger" like the sample below: package Test; im...