TL;DR Компилятор Eclipse генерирует сигнатуру метода для экземпляра лямбды, которая недействительна в соответствии со спецификацией. Из-за дополнительного кода проверки типов, добавленного в JDK 9 для лучшего соблюдения спецификации, неправильная подпись теперь вызывает исключение при работе на Java 11.
Проверено с Eclipse 2019-03, а также с этим кодом:
public class Main {
public static void main(String[] args) {
getHasValue().addValueChangeListener(evt -> {});
}
public static HasValue<?, ?> getHasValue() {
return null;
}
}
interface HasValue<E extends HasValue.ValueChangeEvent<V>,V> {
public static interface ValueChangeEvent<V> {}
public static interface ValueChangeListener<E extends HasValue.ValueChangeEvent<?>> {
void valueChanged(E event);
}
void addValueChangeListener(HasValue.ValueChangeListener<? super E> listener);
}
Даже при использовании null
в качестве приемника код дает сбой при начальной загрузке с той же ошибкой.
Используя javap -v Main
, мы можем увидеть, в чем проблема. Я вижу это в таблице BoostrapMethods:
BootstrapMethods:
0: #48 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#50 (Lmain/HasValue$ValueChangeEvent;)V
#53 REF_invokeStatic main/Main.lambda$0:(Ljava/lang/Object;)V
#54 (Ljava/lang/Object;)V
Обратите внимание, что последний аргумент (константа #54) равен (Ljava/lang/Object;)V
, а javac
генерирует (Lmain/HasValue$ValueChangeEvent;)V
. т. е. сигнатура метода, которую Eclipse хочет использовать для лямбды, отличается от того, что хочет использовать javac
.
Если искомая сигнатура метода является стиранием целевого метода (что, кажется, имеет место), то правильная сигнатура метода действительно (Lmain/HasValue$ValueChangeEvent;)V
, поскольку это стирание целевого метода, а именно:
void valueChanged(E event);
Где E
— это E extends HasValue.ValueChangeEvent<?>
, чтобы было стерто до HasValue.ValueChangeEvent
.
Проблема, похоже, связана с ECJ и, похоже, была обнаружена JDK-8173587. (revision) (к сожалению, это похоже на частный билет.), который добавляет дополнительные проверки типа, чтобы убедиться, что тип метода SAM действительно совместим с типом метода создания экземпляра. Согласно документации LambdaMetafactory::metafactory
тип инстанцируемого метода должен быть таким же или специализации типа метода SAM:
instanceiatedMethodType — подпись и тип возвращаемого значения, которые должны применяться динамически во время вызова. Это может быть то же самое, что и samMethodType, или его специализация.
тип метода, сгенерированный ECJ, очевидно, не является, поэтому это приводит к возникновению исключения. (хотя, честно говоря, я нигде не вижу определения, что представляет собой «специализацию» в данном случае). Я сообщил об этом здесь: https://bugs.eclipse.org/bugs/show_bug.cgi?id=546161
Я предполагаю, что это изменение было сделано где-то в JDK 9, поскольку исходный код уже был модульным на тот момент, а дата пересмотра довольно ранняя (февраль 2017 г.).
Поскольку javac
генерирует правильную сигнатуру метода, вы можете временно переключиться на нее в качестве обходного пути.
person
Jorn Vernee
schedule
05.04.2019
(HasValue<?,?>) comp
... Такой проверки, хотя и согласованной, не было в коде JDK-8. - person Naman   schedule 05.04.2019addSomeListener
. Он работает без указанной ошибки, и при изменении значения TextField добавленный слушатель выполняется, как и ожидалось. (Протестировано с помощью причала и Java 11:jetty-9.4.11.v20180605; built: 2018-06-05T18:24:03.829Z; git: d5fc0523cfa96bfebfbda19606cad384d772f04c; jvm 11.0.1+13
) - person codinghaus   schedule 05.04.2019javac
. - person Holger   schedule 05.04.2019javap -c <classname>
. Поскольку компилятор не должен изменяться, если вы также не меняете версии Eclipse, это, вероятно, вызвано усилением проверки типов BSM в JDK 11 (т. е. в коде, который создает экземпляр лямбда), который выявляет ошибку в ECJ. - person Jorn Vernee   schedule 05.04.2019