DEV Community

Pramoth Suwanpech
Pramoth Suwanpech

Posted on

[Spring Data JPA] native query no converter for TimeStamp --> LocalDate!!

ถ้าหากเราใช้ Spring Data JPA native query และใช้ projection interface ที่แมป column java.sql.TimeStamp ไปเป็น LocalDate จะไม่สามารถทำได้ เนื่องจาก default converter ไม่มีมาให้ (ถ้าเป็น LocalDateTime มีให้นะครับ)

นอกจากไม่มีมาให้แล้ว error message ที่พ่นออกมาตอนเกิด exception ก็ไม่สื่ออ่านแล้วอาจเข้าใจผิดได้ มันออกมาว่า Projection type must be an interface! ซึ่งไม่ใช่

วิธีแก้ปัญหาคือ เราต้อง custom Converter<Timestamp, LocalDate> เอา แต่ว่า ตอนรีจิสเตอร์ custom converter นี่แหละ จะรีจิสเตอร์ธรรมดาไม่ได้

ถ้าเราทำให้ converter เป็น @Bean หรือ register ผ่าน FormatterRegistry.addConverter() ใน WebMvcConfigurer จะยังไม่ทำให้ Spring Data JPA หยิบ converter ที่เพิ่มเข้าไปมาใช้!!!! เพราะว่า Spring Data Jpa ไม่ได้ใช้ ConversionService ตัวที่มัน default มาให้กับ Spring Boot แต่มันใช้ DefaultConversionService.getSharedInstance() ดังนั้น จะให้มันทำงานได้จะต้องมารีจีสเตอร์ที่ตรงนี้ (วางโค๊ดไว้ใหนสักที่ ที่เป็น initialization method เพราะ เป็น static singleton instance ธรรมดา)

    DefaultConversionService conversionService = (DefaultConversionService) DefaultConversionService.getSharedInstance();
    conversionService.addConverter(new TimeStampToLocalDateConverter());

โค๊ดด้านล่างนี้หยิบมาจากใน Spring Data Jpa ตรงส่วนที่ใช้ ConversionService

        /**
         * Creates a new {@link ProjectingConverter} for the given {@link ReturnedType} and {@link ProjectionFactory}.
         *
         * @param type must not be {@literal null}.
         * @param factory must not be {@literal null}.
         */
        ProjectingConverter(ReturnedType type, ProjectionFactory factory) {
            this(type, factory, DefaultConversionService.getSharedInstance());
        }

จะเห็นว่ามันใช้ DefaultConversionService.getSharedInstance() โดยตรง

Top comments (0)