Как инициализировать переменные в родительском абстрактном классе Spring Bean, используя Kotlin? - PullRequest
0 голосов
/ 23 марта 2020

У меня есть следующая структура Spring Bean

abstract class GenericRepository<T> {

private val FIND_BY_ID_SQL = "SELECT * FROM ${this.getTableName()} WHERE id = ?"

abstract fun getTableName(): String

abstract fun jdbcTemplate(): JdbcTemplate

abstract fun getMapper(): RowMapper<T>

fun find(id: Long): T? {
    return jdbcTemplate().queryForObject(FIND_BY_ID_SQL, arrayOf(id), getMapper())
}
}

Репозиторий пользователя

@Repository
class UserRepository(
    @Autowired
    private val jdbcTemplate: JdbcTemplate
) : GenericRepository<User>() {

companion object {
    private const val INSERT_SQL = "INSERT INTO \"user\"(name, age) VALUES (?,?)"
}

private class LogMapper : RowMapper<User> {
    override fun mapRow(rs: ResultSet, rowNum: Int): User? {
        return User(
                id = rs.getLong("id"),
                name = rs.getString("name"),
                age = rs.getInt("operation")
        )
    }
}

override fun getTableName(): String {
    return "user"
}

override fun jdbcTemplate(): JdbcTemplate {
    return jdbcTemplate
}

override fun getMapper(): RowMapper<User> {
    return LogMapper()
}
}

Проблема, когда Spring создает прокси и создает компонент UserRepository, который не инициализирует FIND_BY_ID_ SQL оставив его пустым.

Null variable

Вопрос: как usign абстрактный класс заставляет пружину инициализировать переменную FIND_BY_ID_ SQL?

UPD

Я использовал @Component вместо @Repository, и проблема была решена. FIND_BY_ID_ SQL больше не равен нулю.

1 Ответ

0 голосов
/ 23 марта 2020

Вы можете обойти эту проблему, сделав ее lazy :

private val FIND_BY_ID_SQL by lazy { "SELECT * FROM ${this.getTableName()} WHERE id = ?" }

Однако сначала вы должны быть уверены, что это реальная проблема (например, когда вы звоните find, вы исключение), поскольку прокси-сервер может просто делегировать «реальное» UserRepository с ненулевым FIND_BY_ID_SQLjdbcTemplate et c.), в зависимости от внутренних деталей Spring.

Кроме того, вы должны быть осторожны, когда ваши свойства суперкласса инициализируются в зависимости от подкласса; Я думаю, что ваша точная ситуация должна работать, но я бы предпочел написать это как

abstract class GenericRepository<T>(val tableName: String) {

    private val FIND_BY_ID_SQL = "SELECT * FROM ${tableName} WHERE id = ?"

    abstract val jdbcTemplate: JdbcTemplate

    abstract val mapper: RowMapper<T>

    fun find(id: Long): T? {
        return jdbcTemplate.queryForObject(FIND_BY_ID_SQL, arrayOf(id), mapper)
    }
}

@Repository
class UserRepository(
    @Autowired
    override val jdbcTemplate: JdbcTemplate
) : GenericRepository<User>("user") { ... }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...