I am developing a repository as a service application. An application that let users create their endpoints with queries via a web interface. This application uses either Hibernate or Eclipselink as a JPA provider. The challenge is to check if the supplied user string (query) is a native SQL or a JPQL and that Eclipselink and Hibernate handles this differently, so I decided to wrap it behind this simple checker.

QueryTypeChecker.java

package com.johnpili.query_type_checker;

import jakarta.persistence.Query;
import org.eclipse.persistence.internal.jpa.EJBQueryImpl;
import org.hibernate.query.sql.internal.NativeQueryImpl;
import org.hibernate.query.sqm.internal.QuerySqmImpl;

public interface QueryTypeChecker {
    enum QueryType {
        JPQL,
        SQL
    }

    default QueryType getQueryType(Query query) throws Exception {
        if (query instanceof EJBQueryImpl ejbQuery) {
            if(ejbQuery.getDatabaseQuery().isJPQLCallQuery()) {
                return QueryType.JPQL;
            }

            if(ejbQuery.getDatabaseQuery().isSQLCallQuery()) {
                return QueryType.SQL;
            }
        }

        if(query instanceof QuerySqmImpl<?>) {
            return QueryType.JPQL;
        }

        if(query instanceof NativeQueryImpl) {
            return QueryType.SQL;
        }

        throw new Exception("Unknown type");
    }
}

TestApplication.java

package com.johnpili.query_type_checker.hibernate;

import com.johnpili.query_type_checker.QueryTypeChecker;
import com.johnpili.query_type_checker.QueryTypeCheckerImpl;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import jakarta.persistence.Query;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class TestApplication {

    QueryTypeChecker queryTypeChecker = new QueryTypeCheckerImpl();

    @Test
    public void testIsSQLQuery() {
        try (EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("my-persistence-unit")) {
            EntityManager entityManager = entityManagerFactory.createEntityManager();
            Query query = entityManager.createNativeQuery("SELECT * FROM material");
            Assertions.assertEquals(QueryTypeChecker.QueryType.SQL, queryTypeChecker.getQueryType(query));
        } catch (Exception exception) {
            Assertions.fail(exception);
        }
    }

    @Test
    public void testIsJPQLQuery() {
        try (EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("my-persistence-unit")) {
            EntityManager entityManager = entityManagerFactory.createEntityManager();
            Query query = entityManager.createQuery("SELECT o FROM ProductionOrder o", ProductionOrder.class);
            Assertions.assertEquals(QueryTypeChecker.QueryType.JPQL, queryTypeChecker.getQueryType(query));
        } catch (Exception exception) {
            Assertions.fail(exception);
        }
    }
}

Source Code

https://github.com/johnpili/jpa-query-type-checker