将springboot java demo转换为kotlin,并遇到类型推断失败的问题。
获取目标结果是一种存储库乐趣
package tacocloud.data
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Repository
import tacocloud.Ingredient
import tacocloud.Type
import java.sql.ResultSet
import java.sql.SQLException
@Repository
class JdbcIngredientRepository
@Autowired
constructor( private val jdbc: JdbcTemplate) : IngredientRepository {
override fun findAll(): Iterable<Ingredient> {
return jdbc.query("select id, name, type from Ingredient"
) { rs, rowNum -> this.mapRowToIngredient(rs, rowNum) }
}
override fun findById(id: String): Ingredient {
return jdbc.queryForObject(
"select id, name, type from Ingredient where id=?",
{ rs, rowNum -> mapRowToIngredient(rs, rowNum)}, arrayOf(id))
}
@Throws(SQLException::class)
private fun mapRowToIngredient(rs: ResultSet, rowNum: Int): Ingredient {
return Ingredient(
rs.getString("id"),
rs.getString("name"),
Type.valueOf(rs.getString("type")))
}
override fun save(ingredient: Ingredient): Ingredient {
jdbc.update(
"insert into Ingredient (id, name, type) values (?, ?, ?)",
ingredient.id,
ingredient.name,
ingredient.type.toString())
return ingredient
}
}
findById功能一直说“错误:(29,21)Kotlin:类型推断失败。预期类型不匹配:推断类型是成分?但成分是预期的。”委托功能mapRowToIngredient(rs:ResultSet,rowNum:Int):成分已经返回成分,而不是成分?
有任何想法吗?
我想,JdbcTemplate
是从Java源代码文件编译的,而在Java中,任何引用都可以指向null
。这就是queryForObject
返回可空类型的原因--Kotlin倾向于将所有Java的引用返回声明视为可为空(有关更多信息,请参阅“platform types”)。
如果queryForObject
返回null
,那么您提供的映射器函数将被省略,并且最终将从函数返回null
。
有可能使findById
函数返回一个可空类型(更改声明,以便它返回一个Ingredient?
),指定一个默认对象,如果queryForObject
返回null
(例如jdbc.queryForObject(...) ?: DEFAULT_RESPONSE
)或返回非强制使用“unboxing”到非null类型(例如jdbc.queryForObject(...)!!
)。
PS:通过id查询得到一个空响应是很常见的(例如,这个id的项目被删除了),并且存储库经常返回可空类型或在这种情况下抛出异常,所以我个人坚持这个解决方案。但是如果你的设计保证在被id查询时总是存在一个项目,我会使用!!
将可空类型强制转换为非可空类。