Я пытаюсь развить API. В рамках этой эволюции мне нужно изменить тип возвращаемого значения метода на подкласс (специализация), чтобы продвинутые клиенты могли получить доступ к новым функциям.
Пример (игнорируем уродливое:
public interface Entity {
boolean a();
}
public interface Intf1 {
Entity entity();
}
public interface Main {
Intf1 intf();
}
Теперь я хочу, чтобы ExtendedEntity, Intf2 и Main были такими:
public interface ExtendedEntity extends Entity {
boolean b();
}
public interface Intf2 extends Intf1 {
ExtendedEntity entity();
}
public interface Main {
Intf2 intf();
}
Однако, поскольку тип возвращаемого значения метода является частью его подписи, клиенты, уже скомпилированные с предыдущей версией кода, показывают ошибки компоновки (метод не найден в iirc).
Я хотел бы добавить метод Main с другим типом возвращаемого значения. Два метода (один, который возвращает супертип, а другой, который возвращает подтип) должны быть сопоставлены с одним и тем же методом реализации (который возвращает подтип). Примечание. Насколько я понимаю, это разрешено JVM, но не спецификацией Java.
Мое решение, которое , похоже, работает, злоупотребляет (у меня нет другого слова для этого) системой классов Java для добавления необходимого интерфейса.
public interface Main_Backward_Compatible {
Intf1 intf();
}
public interface Main extends Main_Backward_Compatible{
Intf2 intf();
}
Теперь у старых клиентов будет правильный метод, возвращаемый в поиск invokevirtual (поскольку метод с правильным типом возврата существует в иерархии типов), и реализация, которая фактически будет работать, будет той, которая возвращает подтип Intf2.
Кажется, работает . Во всех тестах, которые я мог придумать (за исключением рефлексии - но мне все равно, что это за бит), он сделал сработал.
Это всегда будет работать? Верны ли мои рассуждения (о invokevirtual)?
И еще один связанный с этим вопрос - существуют ли инструменты для проверки «реальной» двоичной совместимости? Единственные, что я нашел, рассматривают каждый метод отдельно, но не учитывают иерархию типов.
Спасибо
Ран.
Редактировать - Инструменты, которые я пробовал и нашел "не очень хорошими" (без учета иерархии типов):
- Clirr 0.6.
- Плагин IntelliJ "APIComparator".
Edit2 - Конечно, моим клиентам запрещено создавать классы реализации для моих интерфейсов (думаю, сервисов). Однако, если вы хотите, чтобы пример был завершен, подумайте об абстрактном классе (для Main) вместо интерфейса.