Question

I'm just learning Scala and trying to create different scenarios with Spring.

The following code executes perfectly:

def insert(student: Student): Unit = {

  jdbcTemplate.update("INSERT INTO STUDENT (ID, FIRSTNAME, LASTNAME) VALUES(?,?,?)",
        new PreparedStatementSetter() {
          def setValues(ps: PreparedStatement) {
            ps.setString(1, student.id)
            ps.setString(2, student.firstName)
            ps.setString(3, student.lastName)
          }
        })
    }
  }

However, when I try to create PreparedStatementSetter implicitly, my SQL code fails.

my implicit function is:

implicit def preparedStatementSetterImplicit(student: Student) = {
  new PreparedStatementSetter() {
    def setValues(ps: PreparedStatement) {
      ps.setString(1, student.id)
      ps.setString(2, student.firstName)
      ps.setString(3, student.lastName)
    }
  } 
}

and I'm trying to use it the following way:

def insert(student: Student): Unit = {

  jdbcTemplate.update("INSERT INTO STUDENT (ID, FIRSTNAME, LASTNAME) VALUES(?,?,?)",
                            student)
}

and my SQL insert fails with the following exception:

Exception in thread "main" org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [INSERT INTO STUDENT (ID, FIRSTNAME, LASTNAME) VALUES(?,?,?)]; nested exception is java.sql.SQLSyntaxErrorException: incompatible data type in conversion

What's wrong in my implicit conversion?

Was it helpful?

Solution

The problem is that the compiler doesn't need to do an implicit conversion because jdbcTemplate.update has an overloaded type signature which only requires String and Object... which will match with String and Student without needing an implicit conversion. You can do this explicitly (which I think looks better for readability in code) like this:

  implicit class preparedStatementSetterImplicit(student: Student) {
    def toPreparedStatement() = {
      new PreparedStatementSetter() {
        def setValues(ps: PreparedStatement) {
          ps.setString(1, student.id)
          ps.setString(2, student.firstName)
          ps.setString(3, student.lastName)
        }
      }
    }
  }

 def insert(student: Student) {
            jdbcTemplate.update("INSERT INTO STUDENT (ID, FIRSTNAME, LASTNAME) VALUES(?,?,?)",
                            student.toPreparedStatement())
  }

OTHER TIPS

Have you tried explicitly typing your conversion, like:

implicit def student2pss(student: Student) : PreparedStatementSetter = {...}

Implicit conversions are used only when the type after conversion matches exactly expected type (and without explicit typing your conversion returns something of anonymous type, not exactly PreparedStatementSetter), so I'm not sure whether the conversion is being used at all. Try adding println to the conversion to see if it's getting fired.

EDIT: To solve the issue, you might want to create your own wrapper for JdbcTemplate and provide a conversion to it:

class JdbcTemplateWrapper(val template: JdbcTemplate) {
    def wrappedUpdate[DataType](statement: String, data: DataType)(implicit conv: DataType => PreparedStatementSetter) = {
        template.update(statement, conv(data))
    }
}
object JdbcTemplateWrapper {
    implicit def wrapJdbc(template: JdbcTemplate) = new JdbcTemplateWrapper(template)
}

Having that in scope, a line

jdbcTemplate.customUpdate("INSERT INTO STUDENT (ID, FIRSTNAME, LASTNAME) VALUES(?,?,?)",
                        student)

would first implicitly convert jdbcTemplate to JdbcTemplateWrapper (in order to make it respond to cusomUpdate and then implicitly convert Student to PreparedStatementSetter.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top