Классы данных 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

После некоторого чтения я нашел несколько решений, все из которых мне не очень нравятся.

  1. Не используйте классы данных. Это работает, но оставляет мне задачу реализоватьequals и т.п.
class SubClass4(id: String, val name: String) : DbEntity(id)
  1. Дублируйте поле. Это работает, но в итоге мы получаем два поля, которые могут не синхронизироваться.
data class SubClass3(val subId: String, val name: String) : DbEntity(subId)
  1. Присвойте геттеру другое имя. Это принципиально также дублирует поле, но скрывает геттер.
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)
Другие вопросы по тегам