Search code examples
kotlinspring-data-jpalocaldatespring-boot-starter

Persist LocalDate with Kotlin and SpringBoot


I'm trying Kotlin with SpringBoot and JPA. I try to persist a LocalDate but have an error. Below is the cody of my entity:

@Entity
@Table(name = "season")
data class Season(val name: String,
              @Convert(converter = LocalDateAttributeConverter::class) val from: LocalDate,
              @Convert(converter = LocalDateAttributeConverter::class) val to: LocalDate,
              @Enumerated(EnumType.STRING) val status: Status,
              @Id @GeneratedValue val id: Int = -1)

enum class Status {
    CURRENT, CLOSED
}

The converter:

@Converter(autoApply = true)
class LocalDateAttributeConverter : AttributeConverter<LocalDate, Date> {

    override fun convertToDatabaseColumn(locDate: LocalDate?): Date? {
        return if (locDate == null) null else Date.valueOf(locDate)
    }

    override fun convertToEntityAttribute(sqlDate: Date?): LocalDate? {
        return sqlDate?.toLocalDate()
    }
}

When I try to create the entity:

val season = seasonRepository.save(Season("2017-2018",
        LocalDate.of(2017, Month.SEPTEMBER, 1),
        LocalDate.of(2018, Month.JULY, 31),
        Status.CURRENT))

The error stack is the following one:

Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "SELECT SEASON0_.ID AS ID1_6_0_, SEASON0_.FROM[*] AS FROM2_6_0_, SEASON0_.NAME AS NAME3_6_0_, SEASON0_.STATUS AS STATUS4_6_0_ FROM SEASON SEASON0_ WHERE SEASON0_.ID=? "; expected "identifier"; SQL statement: select season0_.id as id1_6_0_, season0_.from as from2_6_0_, season0_.name as name3_6_0_, season0_.status as status4_6_0_ from season season0_ where season0_.id=? [42001-195] at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) ~[h2-1.4.195.jar:1.4.195] at org.h2.message.DbException.getSyntaxError(DbException.java:205) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.readColumnIdentifier(Parser.java:3241) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.readTermObjectDot(Parser.java:2737) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.readTerm(Parser.java:2863) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.readFactor(Parser.java:2384) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.readSum(Parser.java:2371) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.readConcat(Parser.java:2341) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.readCondition(Parser.java:2172) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.readAnd(Parser.java:2144) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.readExpression(Parser.java:2136) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.parseSelectSimpleSelectPart(Parser.java:2047) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.parseSelectSimple(Parser.java:2079) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.parseSelectSub(Parser.java:1934) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.parseSelectUnion(Parser.java:1749) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.parseSelect(Parser.java:1737) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.parsePrepared(Parser.java:448) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.parse(Parser.java:320) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.parse(Parser.java:292) ~[h2-1.4.195.jar:1.4.195] at org.h2.command.Parser.prepareCommand(Parser.java:257) ~[h2-1.4.195.jar:1.4.195] at org.h2.engine.Session.prepareLocal(Session.java:573) ~[h2-1.4.195.jar:1.4.195] at org.h2.engine.Session.prepareCommand(Session.java:514) ~[h2-1.4.195.jar:1.4.195] at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1204) ~[h2-1.4.195.jar:1.4.195] at org.h2.jdbc.JdbcPreparedStatement.(JdbcPreparedStatement.java:73) ~[h2-1.4.195.jar:1.4.195] at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:288) ~[h2-1.4.195.jar:1.4.195] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151] at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126) ~[tomcat-jdbc-8.5.15.jar:na] at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108) ~[tomcat-jdbc-8.5.15.jar:na] at org.apache.tomcat.jdbc.pool.interceptor.AbstractCreateStatementInterceptor.invoke(AbstractCreateStatementInterceptor.java:75) ~[tomcat-jdbc-8.5.15.jar:na] at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108) ~[tomcat-jdbc-8.5.15.jar:na] at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:81) ~[tomcat-jdbc-8.5.15.jar:na] at com.sun.proxy.$Proxy66.prepareStatement(Unknown Source) ~[na:na] at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:146) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:172) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] ... 67 common frames omitted

Did anyone encounter the same problem?

Thanks beforehand, Romain.


Solution

  • The important part of the error is:

    expected "identifier"; SQL statement: select season0_.id as id1_6_0_, season0_.from as from2_6_0_, (...snip...)

    SQL is expecting an identifier at some point but can't find it. The keyword from is where a column name should be: that's the problem.

    You could rename your from property, or tell JPA that you want to call it something else in SQL, like this:

    @Column(name = "date_from")
    @Convert(converter = LocalDateAttributeConverter::class) val from: LocalDate,