1

I am developing a NamedQueryManager EJB that receives a JPQL string from a client and returns a query that only selects data that the user is authorized to read. For example, if the client program wants Companies, it would create the following query and send to the NamedQueryManager.

  • SELECT c FROM Company c

The NamedQueryManager would consider the query and the current user and if the user doesn't have full permissions to read Company entities would return a query similar to the following:

  • SELECT c FROM Company c where c.reader = :user

Instead of creating my own parser, I investigated EclipseLink 2.6.1 and found that I could perform the following to parse the query:

JPQLExpression jpql = new JPQLExpression(jpqlString, new JPQLGrammar2_1());

if (jpql.getQueryStatement() instanceof SelectStatement) {

    logger.debug("JPQL Expression is a Select statement.");

} else if (jpql.getQueryStatement() instanceof UpdateStatement) {

    logger.debug("JPQL Expression is a Update statement.");

} else if (jpql.getQueryStatement() instanceof DeleteStatement) {

    logger.debug("JPQL Expression is a Delete statement.");

} else {

    logger.debug("JPQL Expression is an unknown statement.");

}

I could then loop through the children of the QueryStatement and determine the pieces of the statement. For example, the following loops through the Select clause.

SelectStatement st = (SelectStatement) jpql.getQueryStatement();

logger.debug("JPQL Select Statement: {}", st);

logger.debug("********************");

SelectClause sc = (SelectClause) st.getSelectClause();

logger.debug("Select Clause: {}", sc);

for (Expression e : sc.children()) {

    logger.debug("Child: {}", e);

}

for (Expression e : sc.orderedChildren()) {

    logger.debug("Ordered Child: {}", e);

}

So my question is am I on the correct path for using EclipseLink to parse and modify my JPQL?

I am comfortable with the parsing but how do I modify? Should I build a new JPQL string using the parsed JPQL or can I add information to the parsed JPQL directly to create the new query?

I began investigating how I could determine if the passed jpql string is valid and found references to the HermesParser class in the org.eclipse.persistence.internal.jpa.jpql package.

Should I stay away from "internal" packages?

I don't think that the following code which I am using to parse the jpql string uses the HermesParser but the org.eclipse.persistence.jpa.jpql.parser package-info states that "This is the core of Hermes,..."

JPQLExpression jpql = new JPQLExpression(jpqlString, new JPQLGrammar2_1()); 

So this leads me to ask what is Hermes?

Any big picture help or references would be greatly appreciated.

Note: This is a continuation of the following question.

Should I use @NamedQuery annotation or addNamedQuery method?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Reed Elliott
  • 223
  • 2
  • 15
  • Your use case seems somewhat bizarre. It smells of poor separation of concerns. Why should a client program know what JPQL even is? If you need queries that are constructed dynamically based on security, filtering criteria etc., you're better off using a `CriteriaQuery`. Parsing and rewriting named queries defeats the purpose of using them (which is to cache precompiled queries). – crizzis Jan 17 '18 at 20:03
  • And yes, you should always stay away from internal packages, because once you start using them, your code becomes dependent on the internal implementation and thus, you're basically stuck with the current version of the library. – crizzis Jan 17 '18 at 20:07
  • Customizing the JPQL parser is a novel idea, but ties the application to only JPQL queries - the same processing will not work for native, criteria or even EclipseLink expression queries. The parser will convert JPQL into an eclipseLink expression with which to build the query, which then gets converted to SQL. You might want to look at query redirectors which can handle modifying all queries. see https://wiki.eclipse.org/Using_Advanced_Query_API_(ELUG) and http://onpersistence.blogspot.com/2010/07/eclipselink-jpa-native-constructor.html – Chris Jan 18 '18 at 14:46
  • Interesting! I am currently planning on using a EJB to build my queries starting with the query provided by the client, but I could use a QueryRedirector to intercept and modify my queries instead. Regardless of the chosen interceptor technique, I still need to review and modify the base query which is what I am struggling with at the moment. – Reed Elliott Jan 19 '18 at 13:07
  • The client in this case is an EJB that is needs data from the database, and the server is the EJB responsible for creating the correct query that will fetch the only the data that the current user is authorized to read. – Reed Elliott Jan 19 '18 at 13:11

0 Answers0