Skip to content

Conversation

@kmvipin
Copy link
Contributor

@kmvipin kmvipin commented Feb 2, 2026

TRUNK-6533: Replace deprecated Hibernate Criteria with JPA Criteria

Description of what I changed

  • Removed all usage of deprecated session.createCriteria()
  • Converted to CriteriaBuilder / CriteriaQuery / Root / Predicate pattern
  • Maintained identical query semantics and results
  • Eliminated deprecation warnings during compilation (-Xlint:deprecation)
  • Prepared codebase for future Hibernate 6 / 7 upgrade
  • No functional changes; unit/integration tests pass unchanged

Issue I worked on

see https://issues.openmrs.org/browse/TRUNK-6533

Checklist: I completed these to help reviewers :)

  • My IDE is configured to follow the code style of this project.

  • I have added tests to cover my changes. (If you refactored
    existing code that was well tested you do not have to add tests)

  • I ran mvn clean package right before creating this pull request and
    added all formatting changes to my commit.

  • All new and existing tests passed.

  • My pull request is based on the latest changes of the master branch.

@kmvipin kmvipin marked this pull request as draft February 2, 2026 18:26
@kmvipin kmvipin marked this pull request as ready for review February 2, 2026 18:58
@kmvipin
Copy link
Contributor Author

kmvipin commented Feb 3, 2026

@dkayiwa , can you please review!

@kmvipin kmvipin requested a review from dkayiwa February 3, 2026 15:13
@kmvipin
Copy link
Contributor Author

kmvipin commented Feb 3, 2026

@dkayiwa, can you please review if all good!

@dkayiwa
Copy link
Member

dkayiwa commented Feb 3, 2026

I find it easier to review smaller pull requests. Can you limit the changes to strictly only switching from hibernate criteria to JPA? You can always open new pull requests for further improvements.

@kmvipin
Copy link
Contributor Author

kmvipin commented Feb 4, 2026

I find it easier to review smaller pull requests. Can you limit the changes to strictly only switching from hibernate criteria to JPA? You can always open new pull requests for further improvements.

@dkayiwa, can you please review now as I have mention only PR specific changes!

*/
@Test
public void saveConceptClass_shouldSaveTheGivenConceptClass() {
int unusedConceptClassId = 123;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind explaining how this is related to the ticket?

Copy link
Contributor Author

@kmvipin kmvipin Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa, It is using the id which is not even present in the database, which causes row deleted or updated exception!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was the exception not happening before your changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previously saveOrUpdate method is used for both save and update, here if id is not present in db then it will recreate the row with new Id.

Now we are using persist() for save and merge for update. If the Id is given for an object it will go for merge and try to fetch corresponding row with the given Id which cause this error!

@kmvipin kmvipin requested a review from dkayiwa February 4, 2026 10:54

String hql = "";

StringBuilder hql = new StringBuilder();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this also related to the ticket?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with String, it does not pass security checks of sonar.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is exactly what i mean by using separate pull requests to improve the existing code. I am just trying to reduce the cognitive load when doing these reviews. Can you take a second look at this? https://opensource.com/article/18/6/anatomy-perfect-pull-request

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is exactly what i mean by using separate pull requests to improve the existing code. I am just trying to reduce the cognitive load when doing these reviews. Can you take a second look at this? https://opensource.com/article/18/6/anatomy-perfect-pull-request

I will replace this section with the required once!

@Override
public ConceptReferenceRange saveConceptReferenceRange(ConceptReferenceRange conceptReferenceRange) {
sessionFactory.getCurrentSession().saveOrUpdate(conceptReferenceRange);
if(conceptReferenceRange == null)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is intentional to fail fast by explicitly checking the ID and throwing a clear exception, instead of relying on saveOrUpdate() to throw an internal IllegalArgumentException for null values.

@kmvipin kmvipin requested a review from dkayiwa February 4, 2026 15:10
@kmvipin
Copy link
Contributor Author

kmvipin commented Feb 4, 2026

@dkayiwa, can you review if all okay?

* @return the single result or null if no result is found
* @throws NonUniqueResultException if more than one result is found
*/
@Deprecated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

@kmvipin kmvipin Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa, as per the deprecation documentation, internal DAO methods are not subject to deprecation. Since this is an internal utility, I’ve removed the annotation.

@kmvipin kmvipin requested a review from dkayiwa February 4, 2026 18:07
public ConceptClass saveConceptClass(ConceptClass cc) throws DAOException {
sessionFactory.getCurrentSession().saveOrUpdate(cc);
Session session = sessionFactory.getCurrentSession();
if(cc.getId() != null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa, reimplemented as per the project’s code style.

@kmvipin kmvipin requested a review from dkayiwa February 5, 2026 08:50
public ConceptClass saveConceptClass(ConceptClass cc) throws DAOException {
sessionFactory.getCurrentSession().saveOrUpdate(cc);
Session session = sessionFactory.getCurrentSession();
if(cc.getId() != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa, I have fixed the changes!

@kmvipin kmvipin force-pushed the TRUNK-6533 branch 2 times, most recently from 8e431ff to f8405fb Compare February 5, 2026 11:01
@kmvipin kmvipin requested a review from dkayiwa February 5, 2026 11:18
public ConceptClass saveConceptClass(ConceptClass cc) throws DAOException {
sessionFactory.getCurrentSession().saveOrUpdate(cc);
Session session = sessionFactory.getCurrentSession();
if (cc.getId() != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is sprinkled in lots of other places. Doesn't it call for creating a utility method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa, can you please review this change!

sessionFactory.getCurrentSession().saveOrUpdate(cc);
return cc;
Session session = sessionFactory.getCurrentSession();
return JpaUtils.saveOrUpdate(session,cc);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We recommend putting a space after the comms.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

public ConceptDatatype saveConceptDatatype(ConceptDatatype cd) throws DAOException {
sessionFactory.getCurrentSession().saveOrUpdate(cd);
return cd;
Session session = sessionFactory.getCurrentSession();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get rid of the session variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

public ConceptReferenceRange saveConceptReferenceRange(ConceptReferenceRange conceptReferenceRange) {
sessionFactory.getCurrentSession().saveOrUpdate(conceptReferenceRange);
return conceptReferenceRange;
if (conceptReferenceRange == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this part of the ticket?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa, There is a test case that verifies this method throws an IllegalArgumentException when null is passed. Previously, saveOrUpdate would throw this exception through its internal logic, but now we need to add an explicit null check first so the expected exception is thrown before proceeding.

* @return the saved or updated entity
*/
public static <T extends BaseOpenmrsObject> T saveOrUpdate(Session session, T entity) {
if (entity.getId() != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this also use the utility method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will add null check in this utility method!

@kmvipin
Copy link
Contributor Author

kmvipin commented Feb 5, 2026

@dkayiwa, can you review if all good!

Query query = sessionFactory.getCurrentSession().createQuery("from ConceptNumeric where conceptId = :conceptId")
.setParameter("conceptId", i);
obj = JpaUtils.getSingleResultOrNull(query);
TypedQuery<ConceptNumeric> sql = sessionFactory.getCurrentSession()
Copy link
Member

@dkayiwa dkayiwa Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this sql or query? In other words, is there a reason why you changed the variable name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name change was unintentional and happened while making multiple changes. I’ll revert it to keep the naming consistent.

@kmvipin
Copy link
Contributor Author

kmvipin commented Feb 6, 2026

@dkayiwa, can you please review!

@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 6, 2026

@kmvipin
Copy link
Contributor Author

kmvipin commented Feb 7, 2026

@dkayiwa @ibacher requested for review, please let me know if there is any further change!

@kmvipin kmvipin closed this Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants