Skip to content

Issue with JPA Parameter binding after upgrading to spring-data-jpa 2.7.4 #2683

@yuvanakannan

Description

@yuvanakannan

After Upgrading to spring boot 2.7.5 from 2.7.4, we can see that the NULL query parameters which involves "LIKE" clause are getting bound as empty strings and not as NULL. The same is bound as NULL, if the query condition is "=".

Looks like the problem is due to usage of newer spring-data-jpa version (2.7.5) in spring boot 2.7.5.
Spring boot 2.7.4 was using spring-data-jpa version -2.7.3 where everything looks fine.

For example

If the query is as below and the p_user_name is passed as NULL,
select user from User where :p_user_name is null or userName = :p_user_name

the parameter is properly getting bound as NULL ->
binding parameter [1] as [VARCHAR] - [null]
binding parameter [2] as [VARCHAR] - [null]

Whereas if the query is changed to like below
select user from User where :p_user_name is null or userName LIKE :p_user_name

the parameter is incorrectly getting bound as EMPTY Strings->
binding parameter [1] as [VARCHAR] - []
binding parameter [2] as [VARCHAR] - []

This is failing the existing functionalities in the application.

There seems to be some changes to StringQuery$LikeParameterBinding class (prepare method).
spring-data-jpa.2.7.3 is straight forward:

                @Nullable
		@Override
		public Object prepare(@Nullable Object value) {

			if (value == null) {
				return null;
			}

			switch (type) {
				case STARTING_WITH:
					return String.format("%s%%", value);
				case ENDING_WITH:
					return String.format("%%%s", value);
				case CONTAINING:
					return String.format("%%%s%%", value);
				case LIKE:
				default:
					return value;
			}
		}

from spring-data-jpa-2.7.4 it uses PersistenceProvider.condense method

                @Nullable
		@Override
		public Object prepare(@Nullable Object value) {

			if (value == null) {
				return null;
			}

			switch (type) {
				case STARTING_WITH:
					return String.format("%s%%", PersistenceProvider.condense(value));
				case ENDING_WITH:
					return String.format("%%%s", PersistenceProvider.condense(value));
				case CONTAINING:
					return String.format("%%%s%%", PersistenceProvider.condense(value));
				case LIKE:
				default:
					return PersistenceProvider.condense(value);
			}
		}

This Persistence Provider is returning empty string for some reason when the parameter value is NULL.

public static Object condense(Object value) {

		ClassLoader classLoader = PersistenceProvider.class.getClassLoader();

		if (ClassUtils.isPresent("org.hibernate.jpa.TypedParameterValue", classLoader)) {

			try {

				Class<?> typeParameterValue = ClassUtils.forName("org.hibernate.jpa.TypedParameterValue", classLoader);

				if (typeParameterValue.isInstance(value)) {
					return "";
				}
			} catch (ClassNotFoundException | LinkageError o_O) {
				return value;
			}
		}

		return value;
	}

It might not have been a problem if it is just changing the parameter at the LIKE position, But as the same named parameter is used else where, the parameter value is bound as EMPTY string at all places which is creating the problem.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions