Validate IN expression syntax with a collection-valued input parameter

The Java Persistence API (JPA) specification for IN expressions defines that a collection-valued input parameter is not surrounded by parentheses. OpenJPA allows the parentheses to be present, whereas EclipseLink throws an exception when you call the Query.setParameter method with a collection object corresponding to an IN collection-valued input parameter in parentheses.

This rule detects strings containing Java Persistence Query Language (JPQL) statements with IN expressions that have a single parameter enclosed by parentheses. Because the query string and the corresponding call to setParameter might be in different classes, the rule cannot guarantee that the parameter is a collection. If the parameter is a collection type, remove the parentheses from the query string. Note that parentheses are valid for literals or single-valued input parameters, so be careful about what you remove.

This problem is resolved by removing the parentheses from an IN expression with a collection-valued input parameter.

For example, OpenJPA allows the parentheses in the following query strings, but EclipseLink throws an exception when you call setParameter and try to set ids to a value that is a collection.

  List<String> idList = getIdsToQuery();
  Query query = em.createQuery("SELECT p FROM Person p WHERE p.id IN (:ids)");
  query.setParameter("ids", idList);
  
  final String ENTITY_NAME = "Person";
  final String PRIMARY_KEY = "id";
  List<String> idList2 = getIdsToQuery();
  Query query = em.createQuery("SELECT p FROM " + ENTITY_NAME + " p " +" WHERE p." + PRIMARY_KEY + " IN (:ids)");
  query.setParameter("ids", idList2);

To fix this problem, remove the parentheses when ids represents a collection.

  List<String> idList = getIdsToQuery();
  Query query = em.createQuery("SELECT p FROM Person p WHERE p.id IN :ids");
  query.setParameter("ids", idList);
  
  final String ENTITY_NAME = "Person";
  final String PRIMARY_KEY = "id";
  List<String> idList2 = getIdsToQuery();
  Query query = em.createQuery("SELECT p FROM " + ENTITY_NAME + " p " +" WHERE p." + PRIMARY_KEY + " IN :ids");
  query.setParameter("ids", idList2);

The following shows an example that is flagged but should not be changed because id is a single-value parameter.


  String idMatch = getIdToQuery();
  Query query = em.createQuery(SELECT p FROM Person p WHERE p.id IN (:id));
  query.setParameter("id", idMatch);
  

For information about this issue and other OpenJPA to EclipseLink migration issues, see: