skip to Main Content

I’m seeing something strange after upgrading my app to SpringBoot 3 from SpringBoot 2.

The application relies on an existing database (MySQL) which doesn’t use good practices. One of them is using Y N for booleans stored in a VARCHAR.

To make things easier on the Java side, I created a converter that looks like this:

@Converter
public class BooleanToStringConverter implements AttributeConverter<Boolean, String> {

    @Override
    public String convertToDatabaseColumn(Boolean attribute) {
        if (attribute == null) {
            return null;
        }
        return attribute ? "Y" : "N";
    }

    @Override
    public Boolean convertToEntityAttribute(String dbData) {
        if (dbData == null) {
            return null;
        }
        return dbData.equals("Y");
    }
}

And on my beans I use it as:

@Column(name = "DELIVERED")
@Convert(converter = BooleanToStringConverter.class)
private Boolean delivered;

So far so good.

If I create a repository to query all delivered entities I’d write something like this in SpringBoot 2:

List<MyClass> findAllByDeliveredIsTrue();

But if I run this in SpringBoot 3 it returns an empty list.

I need to write the query manually to make it work.

@Query("SELECT c FROM MyClass c WHERE c.delivered = true")
List<MyClass> findAllByDeliveredIsTrue();

Any idea why it’s happening?


Edit:

I’ve enabled SQL Logs and definitely queries are created differently. For sake of simplicity I translated some things on the post because on real scenario the database is in Spanish and it uses S/N instead of Y/N.

Java service
    @PostConstruct
    public void init() {
        log.error("DEBUG INIT");
        repo.findFirstByActiuIsTrueOrderByDataDesc();
        repo.findFirstByActiuIsTrueOrderByDataDesc1(); ///Working case
        log.error("DEBUG END");
    }

Repository

//Failing case
Optional<Condicio> findFirstByActiuIsTrueOrderByDataDesc();


@Query("SELECT c FROM Condicio c WHERE c.actiu = true ORDER BY c.data ASC")
Optional<Condicio> findFirstByActiuIsTrueOrderByDataDesc1(); //Working case

2023-05-13T10:23:19.336+02:00 ERROR 42936 --- [  restartedMain] c.n.a.backend.service.CondicioService    : DEBUG INIT
Hibernate: select c1_0.COND_CONDICIO,c1_0.COND_ACTIU,c1_0.COND_DATA,c1_0.COND_DESCRIPCIO from CONDICIONS c1_0 where c1_0.COND_ACTIU order by c1_0.COND_DATA desc limit ?
Hibernate: select c1_0.COND_CONDICIO,c1_0.COND_ACTIU,c1_0.COND_DATA,c1_0.COND_DESCRIPCIO from CONDICIONS c1_0 where c1_0.COND_ACTIU='S' order by c1_0.COND_DATA asc
2023-05-13T10:23:19.451+02:00 ERROR 42936 --- [  restartedMain] c.n.a.backend.service.CondicioService    : DEBUG END

2

Answers


  1. Chosen as BEST ANSWER

    It turns out it's an issue on CriteriaBuilder on Spring Data. The issue is being tracked on the repository issue #2800. At the moment of answering it's still not resolved and affected versions are at least Spring Boot 3.0.2


  2. The code you showed does not work with a boolean, but rather a tri-state value. Decide what you will do with NULLs. Then be sure to have 3 cases throughout your code.

    I would not bother trying to fix the yes/no being in a VARCHAR unless you can actually fix the schema and the data. Instead, test for == 'N' as needed. (I picked the "no" side because that works with most European languages.

    Note, however, that == 'Y' is not the same as != 'N' — because of the NULL option.

    Also, check that the COLLATION of that VARCHAR is case-folding so that ‘n’ == ‘N’. The collation name should end in `_ci“.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search