11

Q. Why JPA Projection can't convert Mysql bit(1) to Java Boolean?

Spring Jpa Projection occur error Projection type must be an interface! when the Mysql bit(1) type maps to the Java Boolean type.

Jpa converts a Boolean column in Entity class to bit(1) column in Mysql Table.

If I change getIsBasic's type in PlanInfoProjection interface Integer to Boolean, It doesn't work. Why does it occur error?

JPA Repository

@Query(nativeQuery=true, value="select true as isBasic from dual")
ProductOrderDto.PlanInfoProjection findPlanInfoById(Long id);

Projection interface

public class ProductOrderDto {

    @Getter
    public static class PlanInfo {
        private Boolean isBasic;

        public PlanInfo(PlanInfoProjection projection) {
            // this.isBasic = projection.getIsBasic(); //<-- I want to use like this.
            if (projection.getIsBasic() == null) {
                this.isBasic = null;
            } else {
                this.isBasic = projection.getIsBasic() == 0 ? false : true; // <-- I have to convert
            }
        }
    }
    public interface PlanInfoProjection {
        Integer getIsBasic();    // It works, but I have to convert Integer to Boolean to use. 
        //Boolean getIsBasic();  // doesn't work, but why???
        //Boolean isBasic();     // also doesn't work
        //boolean isBasic();     // also doesn't work
    }
}
hynuah_iia
  • 429
  • 7
  • 14
  • i was having this issue couple of days ago, i take the property as Integer and manipulated in the code with an if statement. It's not a perfect solution but it'll save you i guess.Maybe this solution will work for you https://stackoverflow.com/a/12052390/10909386 – isa_toltar Mar 23 '21 at 12:12
  • @IsaToltar thank you for the comment. I also temporarily set the type of 'isBasic' column `Integer` instead of `Boolean`. and it works okay. I just want to know why jpa projection can't map `mysql bit(1)` to `java Boolean`. – hynuah_iia Mar 23 '21 at 12:17
  • I added more information on the content! – hynuah_iia Mar 23 '21 at 12:35
  • If you have Java 8 you could use only the Interface and add a default method which would convert the Integer to a Boolean. – Robert Niestroj Mar 23 '21 at 14:36
  • @RobertNiestroj I'm using Java 8! `Integer getIsBasic()` works! but `Boolean getIsBasic()` doesn't work! I have to convert Integer to Boolean. – hynuah_iia Apr 28 '21 at 05:23

2 Answers2

8

It seems like this doesn't work out of the box. What works for me (although I'm using DB2 so my datatype is different but this shouldn't be a problem) is to annotate it and use SpEL like this:

    @Value("#{target.isBasic == 1}")
    boolean getIsBasic();

This just takes your int value (0 for false, 1 for true) and returns a boolean value. Should also work with Boolean but I didn't test it.

Another option is to use @Value("#{T(Boolean).valueOf(target.isBasic)}") but this only works for String values, so you would have to store 'true' or 'false' in your database. With T() you can import Static classes into Spring Expression Language, and then just call the valueOf method which returns a boolean (either Boolean or boolean)

ch1ll
  • 419
  • 7
  • 20
0

Solution from ch1ll doesnt work in my case. What works is field and method naming;

select flag from some_table;  // in this example flag is field with boolean type
Method name in interface projection - "boolean isFlag()"

No getFlag(), neither getIsFlag(). If the name Of the field is "isFlag", the method would be boolean isIsFlag(), but i didnt try.

BOTU
  • 75
  • 1
  • 10