Классы данных Kotlin с суперклассом Java
У меня есть класс Java, который содержит общую информацию об объектах базы данных (т.е. их идентификатор).
@Data
public class DbEntity {
protected final String id;
public DbEntity(String id) {
this.id = id;
}
}
Мы используем Ломбок @Data
для генерации геттеров, toString
, equals
...
В Java я бы просто расширил этот класс и добавил @Data
снова.
@Data
class JavaSubClass extends DbEntity {
public JavaSubClass(String id) {
super(id);
}
}
В новом сервисе мы используем Kotlin, но хотели бы повторно использовать стандартные классы, такие как DbEntity
.
Мой первый подход заключался в том, чтобы просто объявить класс данных, например
data class SubClass1(val id: String, val name: String) : DbEntity(id)
Accidental override: The following declarations have the same JVM signature (getId()Ljava/lang/String;):
fun <get-id>(): String defined in com.demo.SubClass1
fun getId(): String! defined in com.demo.SubClass1
После некоторого чтения я нашел несколько решений, все из которых мне не очень нравятся.
- Не используйте классы данных. Это работает, но оставляет мне задачу реализовать
equals
и т.п.
class SubClass4(id: String, val name: String) : DbEntity(id)
- Дублируйте поле. Это работает, но в итоге мы получаем два поля, которые могут не синхронизироваться.
data class SubClass3(val subId: String, val name: String) : DbEntity(subId)
- Присвойте геттеру другое имя. Это принципиально также дублирует поле, но скрывает геттер.
data class SubClass2(@get:JvmName("getId_") val id: String, val name: String) : DbEntity(id)
Как я уже сказал, меня не устраивает ни одно из представленных выше решений. Вместо этого, безусловно, было бы более подходящим иметь абстрактный суперкласс или интерфейс. Однако класс Entity находится в библиотеке, от которой в основном зависят проекты Java. Я не решаюсь менять его только из-за новой зависимости от Котлина.
Кто-нибудь сталкивался с подобными проблемами и есть советы, как их решить?
1 ответ
В качестве обходного пути, пока свойства KT-6653 - Kotlin не переопределяют методы получения и установки в стиле Java, не будут исправлены, я бы выбрал вариант вашей точки 3, то есть:
data class SubClass(@get:JvmName("bogusId") private val id: String, val name: String) : DbEntity(id)
Преимущество этого варианта в том, что вы всегда получаете доступ к "оригиналу" getId
-функция. Вы не будете использоватьbogusId()
-функция, поскольку она не видна / недоступна (доступ к ней через отражение не имеет смысла... вас интересуют только фактические id
-поле). Это работает и выглядит одинаково для обеих сторон: как с Java, так и с Kotlin. Тем не менее, под капотом этот вариант использует 2 поля, но в лучшем случае вы можете просто заменить его в будущем чем-то вроде:
data class SubClass(override val id: String, val name : String) : DbEntity(id)