Cannot invoke "...getJdbcValueBinder()" because "jdbcMapping" is null
Asked Answered
E

3

10

When I run my Spring Boot application, everything works fine: Hibernate generates tables and populates them with a LoadDatabase configuration class.

I have a TestController that I use to test whether my SQL queries defined in repository classes work correctly. Once I try to go to a test endpoint and query some data from the database, I get the following error:

java.lang.NullPointerException: Cannot invoke "org.hibernate.metamodel.mapping.JdbcMapping.getJdbcValueBinder()" because "jdbcMapping" is null

What can it be? Some problems with model classes? Please, write a comment if I should provide more information.

LoadDatabase class:

@Configuration
public class LoadDatabase {

    @Bean
    CommandLineRunner initDatabase(CleanerRepository cleanerRepository,
                                   RoomRepository roomRepository,
                                   CleanerScheduleRecordRepository cleanerScheduleRecordRepository) {

        /* HOTEL CLEANERS */
        Cleaner cleaner1 = new Cleaner(1, "John", "", "Doe");
        Cleaner cleaner2 = new Cleaner(2, "Petro", "Olehovich", "Petrov");
        Cleaner cleaner3 = new Cleaner(3, "Karl", "", "Johnson");

        /* ROOMS ON THE FLOOR #1 */
        Room floor1_room1 = new Room(101, "155-44-33", RoomType.ONE_GUEST, true);
        Room floor1_room2 = new Room(102, "111-22-33", RoomType.ONE_GUEST, true);
        Room floor1_room3 = new Room(103, "124-54-22", RoomType.ONE_GUEST, true);
        Room floor1_room4 = new Room(104, "125-43-22", RoomType.TWO_GUESTS, true);
        Room floor1_room5 = new Room(105, "123-65-93", RoomType.TWO_GUESTS, true);
        Room floor1_room6 = new Room(106, "173-43-32", RoomType.TWO_GUESTS, true);
        Room floor1_room7 = new Room(107, "184-77-22", RoomType.THREE_GUESTS, true);
        Room floor1_room8 = new Room(108, "164-29-54", RoomType.THREE_GUESTS, true);
        Room floor1_room9 = new Room(109, "175-88-99", RoomType.THREE_GUESTS, true);

        /* ROOMS ON THE FLOOR #2 */
        Room floor2_room1 = new Room(201, "237-44-33", RoomType.ONE_GUEST, true);
        Room floor2_room2 = new Room(202, "211-22-33", RoomType.ONE_GUEST, true);
        Room floor2_room3 = new Room(203, "224-54-22", RoomType.ONE_GUEST, true);
        Room floor2_room4 = new Room(204, "225-43-22", RoomType.TWO_GUESTS, true);
        Room floor2_room5 = new Room(205, "223-65-93", RoomType.TWO_GUESTS, true);
        Room floor2_room6 = new Room(206, "273-43-32", RoomType.TWO_GUESTS, true);
        Room floor2_room7 = new Room(207, "284-77-22", RoomType.THREE_GUESTS, true);
        Room floor2_room8 = new Room(208, "264-29-54", RoomType.THREE_GUESTS, true);
        Room floor2_room9 = new Room(209, "275-88-99", RoomType.THREE_GUESTS, true);

        /* ROOMS ON THE FLOOR #3 */
        Room floor3_room1 = new Room(301, "355-44-33", RoomType.ONE_GUEST, true);
        Room floor3_room2 = new Room(302, "311-22-33", RoomType.ONE_GUEST, true);
        Room floor3_room3 = new Room(303, "324-54-22", RoomType.ONE_GUEST, true);
        Room floor3_room4 = new Room(304, "325-43-22", RoomType.TWO_GUESTS, true);
        Room floor3_room5 = new Room(305, "323-65-93", RoomType.TWO_GUESTS, true);
        Room floor3_room6 = new Room(306, "373-43-32", RoomType.TWO_GUESTS, true);
        Room floor3_room7 = new Room(307, "384-77-22", RoomType.THREE_GUESTS, true);
        Room floor3_room8 = new Room(308, "364-29-54", RoomType.THREE_GUESTS, true);
        Room floor3_room9 = new Room(309, "375-88-99", RoomType.THREE_GUESTS, true);

        /* CLEANERS' SCHEDULE RECORDS */
        CleanerScheduleRecord record1 = new CleanerScheduleRecord(cleaner1, DayOfWeek.SUNDAY, 1);
        CleanerScheduleRecord record2 = new CleanerScheduleRecord(cleaner1, DayOfWeek.MONDAY, 2);
        CleanerScheduleRecord record3 = new CleanerScheduleRecord(cleaner1, DayOfWeek.TUESDAY, 3);
        CleanerScheduleRecord record4 = new CleanerScheduleRecord(cleaner1, DayOfWeek.WEDNESDAY, 1);
        CleanerScheduleRecord record5 = new CleanerScheduleRecord(cleaner1, DayOfWeek.THURSDAY, 2);
        CleanerScheduleRecord record6 = new CleanerScheduleRecord(cleaner1, DayOfWeek.FRIDAY, 3);
        CleanerScheduleRecord record7 = new CleanerScheduleRecord(cleaner1, DayOfWeek.SATURDAY, 1);

        CleanerScheduleRecord record8 = new CleanerScheduleRecord(cleaner2, DayOfWeek.SUNDAY, 3);
        CleanerScheduleRecord record9 = new CleanerScheduleRecord(cleaner2, DayOfWeek.MONDAY, 1);
        CleanerScheduleRecord record10 = new CleanerScheduleRecord(cleaner2, DayOfWeek.TUESDAY, 2);
        CleanerScheduleRecord record11 = new CleanerScheduleRecord(cleaner2, DayOfWeek.WEDNESDAY, 3);
        CleanerScheduleRecord record12 = new CleanerScheduleRecord(cleaner2, DayOfWeek.THURSDAY, 1);
        CleanerScheduleRecord record13 = new CleanerScheduleRecord(cleaner2, DayOfWeek.FRIDAY, 2);
        CleanerScheduleRecord record14 = new CleanerScheduleRecord(cleaner2, DayOfWeek.SATURDAY, 3);

        CleanerScheduleRecord record15 = new CleanerScheduleRecord(cleaner3, DayOfWeek.SUNDAY, 2);
        CleanerScheduleRecord record16 = new CleanerScheduleRecord(cleaner3, DayOfWeek.MONDAY, 3);
        CleanerScheduleRecord record17 = new CleanerScheduleRecord(cleaner3, DayOfWeek.TUESDAY, 1);
        CleanerScheduleRecord record18 = new CleanerScheduleRecord(cleaner3, DayOfWeek.WEDNESDAY, 2);
        CleanerScheduleRecord record19 = new CleanerScheduleRecord(cleaner3, DayOfWeek.THURSDAY, 3);
        CleanerScheduleRecord record20 = new CleanerScheduleRecord(cleaner3, DayOfWeek.FRIDAY, 1);
        CleanerScheduleRecord record21 = new CleanerScheduleRecord(cleaner3, DayOfWeek.SATURDAY, 2);

        return args -> {
            cleanerRepository.saveAll(Arrays.asList(cleaner1, cleaner2, cleaner3));

            roomRepository.saveAll(Arrays.asList(floor1_room1, floor1_room2, floor1_room3, floor1_room4, floor1_room5, floor1_room6, floor1_room7, floor1_room8, floor1_room9));
            roomRepository.saveAll(Arrays.asList(floor2_room1, floor2_room2, floor2_room3, floor2_room4, floor2_room5, floor2_room6, floor2_room7, floor2_room8, floor2_room9));
            roomRepository.saveAll(Arrays.asList(floor3_room1, floor3_room2, floor3_room3, floor3_room4, floor3_room5, floor3_room6, floor3_room7, floor3_room8, floor3_room9));

            cleanerScheduleRecordRepository.saveAll(Arrays.asList(record1, record2, record3, record4, record5, record6, record7, record8, record9, record10, record11,
                    record12, record13, record14, record15, record16, record17, record18, record19, record20, record21));
        };
    }
}

TestController class:

@Controller
@RequestMapping(path = "/test")
public class TestController {

    private final AdministrationService administrationService;

    @Autowired
    public TestController(AdministrationService administrationService) {
        this.administrationService = administrationService;
    }

    @GetMapping(path = "/")
    public String areThereAvailableRooms() {
        System.out.println(administrationService.areThereAvailableRooms());
        System.out.println(administrationService.getCleanerInfoByDayAndFloor("MONDAY", 3));
        return "hello";
    }
}

AdministrationService class:

@Service
public class AdministrationService {

    private final CleanerService cleanerService;
    private final GuestService guestService;
    private final RoomService roomService;

    @Autowired
    public AdministrationService(CleanerService cleanerService, GuestService guestService, RoomService roomService) {
        this.cleanerService = cleanerService;
        this.guestService = guestService;
        this.roomService = roomService;
    }

    public List<Guest> getGuestsInfoByRoomNumber(Integer roomNumber) {
        return guestService.getGuestsInfoByRoom(roomNumber);
    }

    public List<Guest> getGuestsInfoByCity(String city) {
        return guestService.getGuestsByCity(city);
    }

    public Cleaner getCleanerInfoByDayAndFloor(String day, Integer floorNumber) {
        return cleanerService.getCleanerByFloorAndDay(DayOfWeek.valueOf(day), floorNumber);
    }

    public boolean areThereAvailableRooms() {
        return roomService.areThereAvailableRooms();
    }

    public Long getNumberOfAvailableRooms() {
        return roomService.getNumberOfAvailableRooms();
    }

    public void hireCleaner(Cleaner cleaner) {
        cleanerService.hireNewCleaner(cleaner);
    }

    public void layOffCleaner(Cleaner cleaner) {
        cleanerService.layOffCleaner(cleaner);
    }

    public void changeCleanerSchedule(Cleaner cleaner, String day, Integer floorNumber) {
        cleanerService.changeCleanerSchedule(cleaner, DayOfWeek.valueOf(day), floorNumber);
    }

    public void checkInGuests(Guest... guests) {
        checkInGuestsAndReserveRoom(guests);
    }

    public void checkOutGuestsByRoomNumber(Integer roomNumber) {
        checkOutGuestsAndFreeUpRoom(roomNumber);
    }

    private void checkInGuestsAndReserveRoom(Guest... guests) {
        String suitableRoomType = getSuitableRoomType(guests.length);
        Integer roomNumber = roomService.findFirstAvailableRoomNumberDependingOnType(String.valueOf(suitableRoomType));
        guestService.checkInGuestsInRoom(roomNumber, guests);
        roomService.setAvailableToFalse(roomNumber);
    }

    private String getSuitableRoomType(int numberOfGuests) {
        return switch (numberOfGuests) {
            case (1) -> String.valueOf(RoomType.ONE_GUEST);
            case (2) -> String.valueOf(RoomType.TWO_GUESTS);
            case (3) -> String.valueOf(RoomType.THREE_GUESTS);
            default ->
                    throw new NoAvailableRoomTypeException(String.format("There is no room for %s guests!", numberOfGuests));
        };
    }

    private void checkOutGuestsAndFreeUpRoom(Integer roomNumber) {
        guestService.checkOutGuestsFromRoom(roomNumber);
        roomService.setAvailableToTrue(roomNumber);
    }
}

CleanerRepository interface:

@Repository
public interface CleanerRepository extends JpaRepository<Cleaner, Integer> {

    @Query(value = "SELECT * FROM hotel_management_system.cleaner clnr JOIN hotel_management_system.cleaner_schedule_record csr on clnr.cleaner_id = csr.cleaner_cleaner_id" +
            " WHERE csr.week_day=?1 AND csr.floor_number=?2", nativeQuery = true)
    Optional<Cleaner> findCleanerByFloorAndDay(DayOfWeek day, Integer floorNumber);

}

EDIT: Model classes:

@Entity(name = "cleaner")
public class Cleaner {

    @Id
    @GeneratedValue
    @Column(name = "cleaner_id")
    private Integer cleanerID;

    @Column(name = "first_name", nullable = false)
    private String firstName;

    @Column(name = "middle_name")
    private String middleName;

    @Column(name = "last_name", nullable = false)
    private String lastName;

    @OneToMany(mappedBy = "cleaner", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<CleanerScheduleRecord> scheduleRecords = new ArrayList<>();

    public Cleaner() {
    }

    public Cleaner(Integer cleanerID, String firstName, String middleName, String lastName) {
        this.cleanerID = cleanerID;
        this.firstName = firstName;
        this.middleName = middleName;
        this.lastName = lastName;
    }

    public Integer getCleanerID() {
        return cleanerID;
    }
}

@Entity(name = "cleaner_schedule_record")
public class CleanerScheduleRecord {

    @Id
    @GeneratedValue
    @Column(name = "record_id")
    private Integer recordID;

    @ManyToOne(fetch = FetchType.LAZY)
    private Cleaner cleaner;

    @Enumerated(EnumType.STRING)
    @Column(name = "week_day", nullable = false)
    private DayOfWeek dayOfWeek;

    @Column(name = "floor_number", nullable = false)
    private Integer floorNumber;

    public CleanerScheduleRecord() {

    }

    public CleanerScheduleRecord(Cleaner cleaner, DayOfWeek dayOfWeek, Integer floorNumber) {
        this.cleaner = cleaner;
        this.dayOfWeek = dayOfWeek;
        this.floorNumber = floorNumber;
    }

}
Entity answered 1/5, 2023 at 6:15 Comment(0)
E
21

The problem was that was passing an enum type DayOfWeek as a parameter to my findCleanerByFloorAndDay query-method instead of a plain string in the CleanerRepository interface.

Entity answered 1/5, 2023 at 7:25 Comment(3)
could you explain a bit more? Are you storing DayOfWeek as strings in your database?Franklynfrankness
@Maurice, yes, I'm storing DayOfWeek as strings in the database. The problem was that I was passing precisely the type of DayOfWeek instead of String to the parameters of the repository method intended to save information.Entity
i just found out today that this is also a problem when using enums in @Procedure annotation: you need to pass in the enum as String type or you get this weird org.springframework.dao.InvalidDataAccessApiUsageException: Cannot determine the bindable type for procedure parameter: null errorGunilla
S
4

Mapping doesn't work for named parameters in native queries.

As a workaround you can use Spring Expression Language (SpEL)

@Repository
public interface CleanerRepository extends JpaRepository<Cleaner, Integer> {

@Query(value = "SELECT * FROM hotel WHERE day=:#{#day.name()} AND floor=:floor", 
nativeQuery = true)
Optional<Cleaner> find(@Param("day") DayOfWeek day, @Param("floor") Integer floorNumber);
}
Scotopia answered 21/5, 2023 at 3:33 Comment(0)
T
2

The same exception here. This is how I solved it.

//My entity
private EnumSet<MyEnum> enumSet;

//part of my string SQL
"status IN :status"

//Setting parameters to my NativeQuery
query.setParameter("status", enumSet.stream().map(Enum::name).toList());
Tavi answered 5/12, 2023 at 14:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.