Я хотел бы спросить, возможно ли в Java 8+ объявить общую границу T
, чтобы она расширяла суперкласс / суперинтерфейс U
(который может быть Object
или Serializable
), но ломается компиляция , если T
расширяется L
(который должен сначала расширяться U
).
Я обнаружил эту проблему, используя объекты диапазона фильтра: один из моих разработчиков вызвал неправильный метод и провел много времени, спрашивая, почему он дает противоречивые результаты. Поэтому я хотел как-то помочь ей изменить сигнатуру метода, чтобы на раннем этапе обнаружить, что она использует неправильный код.
Я покажу свой пример в очень упрощенном виде. Речь идет о таблицах и динамических фильтрах.
#Displays a text "[field name] is equal to [value]"
#Value (T) must be Oject
#Internally uses Object::toString
#Null shows blank string
public static String <T> localizeEq(Localizable fieldName, T value);
<LocalDate> localize(forI18nLabel("DATE_OF_BIRTH_LABEL",dateOfBirth)
"Date of birth equals 01/01/1900" (en)
"syntymäaika on 01/01/1990" (fi)
#Additional diplays for "ge, gte, le..."
#Overload methods not displayed
#SimpleFilter is {op:"ge|ge|eq...",value:""}}
#The effective display depends on the op attribute
#Example "[field name] is [operator] [value]"
#Example "[field name] is less or equal than [upper]"
#If <filter != null but filter.op == null || filter.value> the method returns null
public static String <T> localize(Localizable fieldName, SimpleFilter<T> filter)
#localize(forI18nLabel("SALARY"),salaryFilter)
#salaryFilter = {op:"lt",value:10000}
#Salary is less than 10000 (en)
Теперь проблема в том, что верхняя граница U
моих обобщенных элементов равна Serializable
, и разработчик случайно вызвал localizeEq
, который принимает атомарные значения, с параметром типа SimpleFilter<?>
, который расширяется Serializable
. Метод localizeEq
создает текст фильтра "[имя поля] равно {op: null, value: null}".
Основная проблема - проверка нуля. Методы, которые работают с атомарными значениями (например, localizeEq, localizeNe), проверяют, является ли параметр нулевым. Методы, работающие со сложными фильтрами, проверяют, что либо параметр фильтра равен нулю , либо , но его значение равно нулю, прежде чем продолжить.
В этом причина вопроса. Очевидно, я могу (исправлю мой код для того, чтобы) проверить тип параметра value
при вызове метода, но имеет три недостатка:
- Разработчики находят его только во время выполнения
- Разработчики обнаруживают проблему только тогда, когда
value
не равно нулю
- Никто в моей компании не проводит автоматические тесты, поэтому они узнают об этом только при запуске всего приложения и установке фильтра в ненулевое значение. После завершения ручного теста оно никогда не повторяется
[Изменить]
Для моего конкретного случая есть еще одна хитрость, но она включает в себя создание более десятка перегруженных устаревших методов:
@Deprecated
public static String localize[Eq|Ne...](Localizable fieldName, SimpleFilter<?> value){ throw new UnsupportedOperationException("Wrong method");}
[Редактировать 3]
Код включен Суть . Обратите внимание, что в коде репозитория мы статически импортируем методы SimpleFilter.filter
или LocalDateRangeFilter.filter
. В вопросе предполагается, что localize(Localizable,SimpleFilter)
является частью того же класса, что и другие методы. И обратите внимание, что в нашем репозитории есть несколько других классов * RangeFilter, которые поддерживают Joda Time, Java Util Date и NumericRange. Все они страдают от одной и той же проблемы.
В любом случае я хотел бы сосредоточиться на объеме вопроса: запрещение расширения в общем виде, что в JLS кажется невозможным.