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 "=".

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. If I change the version back to 2.7.4, all works fine.

Comment From: wilkinsona

Thanks for the report. I think this is very unlikely to have been caused by Spring Boot itself. More likely is a change in behaviour in either Hibernate or Spring Data JPA (assuming that's what you're using). We upgraded to Hibernate 5.6.12.Final (from 5.6.11.Final) and Spring Data 2021.2.5 (from 2021.2.4) in 2.7.5. Please try downgrading each of these dependencies in turn using the hibernate.version and spring-data-bom.version properties respectively to narrow down the cause of the problem.

Comment From: yuvanakannan

Thanks for the suggestion. Changing the spring-data-bom.version or hibernate.version did not work. While trying to debug more, looks like the problem is triggered from spring-data-jpa.2.7.4 version. Spring boot 2.7.4 is using spring-data-jpa.2.7.3, where everything looks fine. Spring boot 2.7.5 and spring-data-bom 2021.2.4 uses spring-data-jpa.2.7.5 and spring-data-jpa.2.74 respectively. Both fails. 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.

Comment From: wilkinsona

Thanks for narrowing down the cause. Please open a Spring Data JPA issue.