Java Casting: Java 11 throws LambdaConversionException while 1.8 does notIs Java “pass-by-reference” or...
Is it possible to do 50 km distance without any previous training?
I’m planning on buying a laser printer but concerned about the life cycle of toner in the machine
Have astronauts in space suits ever taken selfies? If so, how?
How can bays and straits be determined in a procedurally generated map?
Why are electrically insulating heatsinks so rare? Is it just cost?
Can an x86 CPU running in real mode be considered to be basically an 8086 CPU?
Why did the Germans forbid the possession of pet pigeons in Rostov-on-Don in 1941?
Why do falling prices hurt debtors?
Why does Kotter return in Welcome Back Kotter?
To string or not to string
How to format long polynomial?
Theorems that impeded progress
What are these boxed doors outside store fronts in New York?
Can I make popcorn with any corn?
LaTeX closing $ signs makes cursor jump
What defenses are there against being summoned by the Gate spell?
What's the point of deactivating Num Lock on login screens?
Why, historically, did Gödel think CH was false?
Languages that we cannot (dis)prove to be Context-Free
How does one intimidate enemies without having the capacity for violence?
Smoothness of finite-dimensional functional calculus
Do VLANs within a subnet need to have their own subnet for router on a stick?
What's the output of a record cartridge playing an out-of-speed record
Is it legal for company to use my work email to pretend I still work there?
Java Casting: Java 11 throws LambdaConversionException while 1.8 does not
Is Java “pass-by-reference” or “pass-by-value”?How do I efficiently iterate over each entry in a Java Map?Does a finally block always get executed in Java?How does the Java 'for each' loop work?What is the difference between public, protected, package-private and private in Java?How do I read / convert an InputStream into a String in Java?When to use LinkedList over ArrayList in Java?How do I generate random integers within a specific range in Java?Does Java support default parameter values?Why don't Java's +=, -=, *=, /= compound assignment operators require casting?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
the following code works perfectly fine in a Java 1.8 VM but produces a LambdaConversionException
when executed in a Java 11 VM. Wheres the difference and why does it behave like this?
Code:
public void addSomeListener(Component comp){
if(comp instanceof HasValue) {
((HasValue<?,?>) comp).addValueChangeListener(evt -> {
//do sth with evt
});
}
}
HasValue Javadoc
Exception (V11 only):
Caused by: java.lang.invoke.LambdaConversionException: Type mismatch
for instantiated parameter 0: class java.lang.Object is not a subtype
of interface com.vaadin.flow.component.HasValue$ValueChangeEvent
at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.checkDescriptor(AbstractValidatingLambdaMetafactory.java:308)
at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:294)
at java.base/java.lang.invoke.LambdaMetafactory.altMetafactory(LambdaMetafactory.java:503)
at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:138)
... 73 more
Workaround:
ValueChangeListener<ValueChangeEvent<?>> listener = evt -> {
// do sth with evt
};
((HasValue<?,?>) comp).addValueChangeListener(listener);
System:
OS: Windows 10
IDE: Eclipse 2018-12 (4.10.0)
Java (Compile): JDK 1.8.0_201
Java (Webserver): JDK 11.0.2
Webserver: Wildfly 15
java eclipse java-8 java-11 vaadin-flow
|
show 5 more comments
the following code works perfectly fine in a Java 1.8 VM but produces a LambdaConversionException
when executed in a Java 11 VM. Wheres the difference and why does it behave like this?
Code:
public void addSomeListener(Component comp){
if(comp instanceof HasValue) {
((HasValue<?,?>) comp).addValueChangeListener(evt -> {
//do sth with evt
});
}
}
HasValue Javadoc
Exception (V11 only):
Caused by: java.lang.invoke.LambdaConversionException: Type mismatch
for instantiated parameter 0: class java.lang.Object is not a subtype
of interface com.vaadin.flow.component.HasValue$ValueChangeEvent
at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.checkDescriptor(AbstractValidatingLambdaMetafactory.java:308)
at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:294)
at java.base/java.lang.invoke.LambdaMetafactory.altMetafactory(LambdaMetafactory.java:503)
at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:138)
... 73 more
Workaround:
ValueChangeListener<ValueChangeEvent<?>> listener = evt -> {
// do sth with evt
};
((HasValue<?,?>) comp).addValueChangeListener(listener);
System:
OS: Windows 10
IDE: Eclipse 2018-12 (4.10.0)
Java (Compile): JDK 1.8.0_201
Java (Webserver): JDK 11.0.2
Webserver: Wildfly 15
java eclipse java-8 java-11 vaadin-flow
2
Interesting and yet poor thing there(HasValue<?,?>) comp
... Such validation though agreed didn't exist in the JDK-8 code.
– Naman
yesterday
When exactly do you get this exception? When you add the listener or when the listener is invoked with an event? If the latter, how do you invoke it with an event (show the code place)
– Erwin Bolwidt
yesterday
8
That’s an important information, as Eclipse has its own compiler, so problems caused by the compiler (and this looks much like a compiler problem) do not have to apply tojavac
then.
– Holger
yesterday
2
@JornVernee changing the language level sometimes causes behavioral changes in the compiler.
– Holger
yesterday
1
@CommonMan IJ neither has its own compiler nor is it a Java VM, so it makes no difference in this case whether you write your code with IJ or a text editor.
– howlger
yesterday
|
show 5 more comments
the following code works perfectly fine in a Java 1.8 VM but produces a LambdaConversionException
when executed in a Java 11 VM. Wheres the difference and why does it behave like this?
Code:
public void addSomeListener(Component comp){
if(comp instanceof HasValue) {
((HasValue<?,?>) comp).addValueChangeListener(evt -> {
//do sth with evt
});
}
}
HasValue Javadoc
Exception (V11 only):
Caused by: java.lang.invoke.LambdaConversionException: Type mismatch
for instantiated parameter 0: class java.lang.Object is not a subtype
of interface com.vaadin.flow.component.HasValue$ValueChangeEvent
at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.checkDescriptor(AbstractValidatingLambdaMetafactory.java:308)
at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:294)
at java.base/java.lang.invoke.LambdaMetafactory.altMetafactory(LambdaMetafactory.java:503)
at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:138)
... 73 more
Workaround:
ValueChangeListener<ValueChangeEvent<?>> listener = evt -> {
// do sth with evt
};
((HasValue<?,?>) comp).addValueChangeListener(listener);
System:
OS: Windows 10
IDE: Eclipse 2018-12 (4.10.0)
Java (Compile): JDK 1.8.0_201
Java (Webserver): JDK 11.0.2
Webserver: Wildfly 15
java eclipse java-8 java-11 vaadin-flow
the following code works perfectly fine in a Java 1.8 VM but produces a LambdaConversionException
when executed in a Java 11 VM. Wheres the difference and why does it behave like this?
Code:
public void addSomeListener(Component comp){
if(comp instanceof HasValue) {
((HasValue<?,?>) comp).addValueChangeListener(evt -> {
//do sth with evt
});
}
}
HasValue Javadoc
Exception (V11 only):
Caused by: java.lang.invoke.LambdaConversionException: Type mismatch
for instantiated parameter 0: class java.lang.Object is not a subtype
of interface com.vaadin.flow.component.HasValue$ValueChangeEvent
at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.checkDescriptor(AbstractValidatingLambdaMetafactory.java:308)
at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:294)
at java.base/java.lang.invoke.LambdaMetafactory.altMetafactory(LambdaMetafactory.java:503)
at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:138)
... 73 more
Workaround:
ValueChangeListener<ValueChangeEvent<?>> listener = evt -> {
// do sth with evt
};
((HasValue<?,?>) comp).addValueChangeListener(listener);
System:
OS: Windows 10
IDE: Eclipse 2018-12 (4.10.0)
Java (Compile): JDK 1.8.0_201
Java (Webserver): JDK 11.0.2
Webserver: Wildfly 15
java eclipse java-8 java-11 vaadin-flow
java eclipse java-8 java-11 vaadin-flow
edited yesterday
Gerrit Sedlaczek
asked yesterday
Gerrit SedlaczekGerrit Sedlaczek
5221617
5221617
2
Interesting and yet poor thing there(HasValue<?,?>) comp
... Such validation though agreed didn't exist in the JDK-8 code.
– Naman
yesterday
When exactly do you get this exception? When you add the listener or when the listener is invoked with an event? If the latter, how do you invoke it with an event (show the code place)
– Erwin Bolwidt
yesterday
8
That’s an important information, as Eclipse has its own compiler, so problems caused by the compiler (and this looks much like a compiler problem) do not have to apply tojavac
then.
– Holger
yesterday
2
@JornVernee changing the language level sometimes causes behavioral changes in the compiler.
– Holger
yesterday
1
@CommonMan IJ neither has its own compiler nor is it a Java VM, so it makes no difference in this case whether you write your code with IJ or a text editor.
– howlger
yesterday
|
show 5 more comments
2
Interesting and yet poor thing there(HasValue<?,?>) comp
... Such validation though agreed didn't exist in the JDK-8 code.
– Naman
yesterday
When exactly do you get this exception? When you add the listener or when the listener is invoked with an event? If the latter, how do you invoke it with an event (show the code place)
– Erwin Bolwidt
yesterday
8
That’s an important information, as Eclipse has its own compiler, so problems caused by the compiler (and this looks much like a compiler problem) do not have to apply tojavac
then.
– Holger
yesterday
2
@JornVernee changing the language level sometimes causes behavioral changes in the compiler.
– Holger
yesterday
1
@CommonMan IJ neither has its own compiler nor is it a Java VM, so it makes no difference in this case whether you write your code with IJ or a text editor.
– howlger
yesterday
2
2
Interesting and yet poor thing there
(HasValue<?,?>) comp
... Such validation though agreed didn't exist in the JDK-8 code.– Naman
yesterday
Interesting and yet poor thing there
(HasValue<?,?>) comp
... Such validation though agreed didn't exist in the JDK-8 code.– Naman
yesterday
When exactly do you get this exception? When you add the listener or when the listener is invoked with an event? If the latter, how do you invoke it with an event (show the code place)
– Erwin Bolwidt
yesterday
When exactly do you get this exception? When you add the listener or when the listener is invoked with an event? If the latter, how do you invoke it with an event (show the code place)
– Erwin Bolwidt
yesterday
8
8
That’s an important information, as Eclipse has its own compiler, so problems caused by the compiler (and this looks much like a compiler problem) do not have to apply to
javac
then.– Holger
yesterday
That’s an important information, as Eclipse has its own compiler, so problems caused by the compiler (and this looks much like a compiler problem) do not have to apply to
javac
then.– Holger
yesterday
2
2
@JornVernee changing the language level sometimes causes behavioral changes in the compiler.
– Holger
yesterday
@JornVernee changing the language level sometimes causes behavioral changes in the compiler.
– Holger
yesterday
1
1
@CommonMan IJ neither has its own compiler nor is it a Java VM, so it makes no difference in this case whether you write your code with IJ or a text editor.
– howlger
yesterday
@CommonMan IJ neither has its own compiler nor is it a Java VM, so it makes no difference in this case whether you write your code with IJ or a text editor.
– howlger
yesterday
|
show 5 more comments
1 Answer
1
active
oldest
votes
TL;DR The Eclipse compiler generates a method signature for the lambda instance that is invalid according to the specification. Due to additional type checking code added in JDK 9 to better enforce the specification, the incorrect signature is now causing an exception when running on Java 11.
Verified with Eclipse 2019-03 as well with this code:
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);
}
Even when using null
as the receiver, the code fails when bootstrapping with the same error.
Using javap -v Main
we can see where the problem lies. I'm seeing this in the BoostrapMethods table:
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
Note that the last argument (constant #54) is (Ljava/lang/Object;)V
, while javac
generates (Lmain/HasValue$ValueChangeEvent;)V
. i.e. the method signature that Eclipse wants to use for the lambda is different from what javac
wants to use.
If the wanted method signature is the erasure of the target method (which seems to be the case), then the correct method signature is indeed (Lmain/HasValue$ValueChangeEvent;)V
since that is the erasure of the target method, which is:
void valueChanged(E event);
Where E
is E extends HasValue.ValueChangeEvent<?>
, so that would be erased to HasValue.ValueChangeEvent
.
The problem seems to be with ECJ, and seems to have been brought to the surface by JDK-8173587 (revision) (Unfortunately this seems to be a private ticket.) which adds extra type checks to verify that the SAM method type is actually compatible with the instantiate method type. According to the documentation of LambdaMetafactory::metafactory
the instantiated method type must be the same, or a specialization of the SAM method type:
instantiatedMethodType - The signature and return type that should be enforced dynamically at invocation time. This may be the same as samMethodType, or may be a specialization of it.
which the method type generated by ECJ is evidently not, so this ends up throwing an exception. (though, to be fair, I don't see defined anywhere what constitutes a "specialization" in this case). I've reported this on the Eclipse bugzilla here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=546161
I'm guessing this change was made somewhere in JDK 9, since source code was already modular at that point, and the date of the revision is fairly early (February 2017).
Since javac
generates the correct method signature, you could switch to that for the time being as a workaround.
7
I tend to over-complicate these bytecode related answers (being someone who's used to looking at bytecode). It's hard to find the right balance between sufficient explanation, and keeping the answer succinct. If anything is unclear, please feel free to ask for clarification.
– Jorn Vernee
yesterday
this is not over-complicate and it's an easy to read and understand answer, there simply isn't a better one. I had a pleasure reading it, thank you for taking the time
– Eugene
yesterday
Could you please add a link to the corresponding Eclipse bug?
– howlger
yesterday
@JornVernee Not at all. I think you explain bytecode related answers very well.
– Michael Berry
yesterday
2
@howlger Done: bugs.eclipse.org/bugs/show_bug.cgi?id=546161
– Jorn Vernee
yesterday
|
show 5 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55532055%2fjava-casting-java-11-throws-lambdaconversionexception-while-1-8-does-not%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
TL;DR The Eclipse compiler generates a method signature for the lambda instance that is invalid according to the specification. Due to additional type checking code added in JDK 9 to better enforce the specification, the incorrect signature is now causing an exception when running on Java 11.
Verified with Eclipse 2019-03 as well with this code:
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);
}
Even when using null
as the receiver, the code fails when bootstrapping with the same error.
Using javap -v Main
we can see where the problem lies. I'm seeing this in the BoostrapMethods table:
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
Note that the last argument (constant #54) is (Ljava/lang/Object;)V
, while javac
generates (Lmain/HasValue$ValueChangeEvent;)V
. i.e. the method signature that Eclipse wants to use for the lambda is different from what javac
wants to use.
If the wanted method signature is the erasure of the target method (which seems to be the case), then the correct method signature is indeed (Lmain/HasValue$ValueChangeEvent;)V
since that is the erasure of the target method, which is:
void valueChanged(E event);
Where E
is E extends HasValue.ValueChangeEvent<?>
, so that would be erased to HasValue.ValueChangeEvent
.
The problem seems to be with ECJ, and seems to have been brought to the surface by JDK-8173587 (revision) (Unfortunately this seems to be a private ticket.) which adds extra type checks to verify that the SAM method type is actually compatible with the instantiate method type. According to the documentation of LambdaMetafactory::metafactory
the instantiated method type must be the same, or a specialization of the SAM method type:
instantiatedMethodType - The signature and return type that should be enforced dynamically at invocation time. This may be the same as samMethodType, or may be a specialization of it.
which the method type generated by ECJ is evidently not, so this ends up throwing an exception. (though, to be fair, I don't see defined anywhere what constitutes a "specialization" in this case). I've reported this on the Eclipse bugzilla here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=546161
I'm guessing this change was made somewhere in JDK 9, since source code was already modular at that point, and the date of the revision is fairly early (February 2017).
Since javac
generates the correct method signature, you could switch to that for the time being as a workaround.
7
I tend to over-complicate these bytecode related answers (being someone who's used to looking at bytecode). It's hard to find the right balance between sufficient explanation, and keeping the answer succinct. If anything is unclear, please feel free to ask for clarification.
– Jorn Vernee
yesterday
this is not over-complicate and it's an easy to read and understand answer, there simply isn't a better one. I had a pleasure reading it, thank you for taking the time
– Eugene
yesterday
Could you please add a link to the corresponding Eclipse bug?
– howlger
yesterday
@JornVernee Not at all. I think you explain bytecode related answers very well.
– Michael Berry
yesterday
2
@howlger Done: bugs.eclipse.org/bugs/show_bug.cgi?id=546161
– Jorn Vernee
yesterday
|
show 5 more comments
TL;DR The Eclipse compiler generates a method signature for the lambda instance that is invalid according to the specification. Due to additional type checking code added in JDK 9 to better enforce the specification, the incorrect signature is now causing an exception when running on Java 11.
Verified with Eclipse 2019-03 as well with this code:
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);
}
Even when using null
as the receiver, the code fails when bootstrapping with the same error.
Using javap -v Main
we can see where the problem lies. I'm seeing this in the BoostrapMethods table:
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
Note that the last argument (constant #54) is (Ljava/lang/Object;)V
, while javac
generates (Lmain/HasValue$ValueChangeEvent;)V
. i.e. the method signature that Eclipse wants to use for the lambda is different from what javac
wants to use.
If the wanted method signature is the erasure of the target method (which seems to be the case), then the correct method signature is indeed (Lmain/HasValue$ValueChangeEvent;)V
since that is the erasure of the target method, which is:
void valueChanged(E event);
Where E
is E extends HasValue.ValueChangeEvent<?>
, so that would be erased to HasValue.ValueChangeEvent
.
The problem seems to be with ECJ, and seems to have been brought to the surface by JDK-8173587 (revision) (Unfortunately this seems to be a private ticket.) which adds extra type checks to verify that the SAM method type is actually compatible with the instantiate method type. According to the documentation of LambdaMetafactory::metafactory
the instantiated method type must be the same, or a specialization of the SAM method type:
instantiatedMethodType - The signature and return type that should be enforced dynamically at invocation time. This may be the same as samMethodType, or may be a specialization of it.
which the method type generated by ECJ is evidently not, so this ends up throwing an exception. (though, to be fair, I don't see defined anywhere what constitutes a "specialization" in this case). I've reported this on the Eclipse bugzilla here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=546161
I'm guessing this change was made somewhere in JDK 9, since source code was already modular at that point, and the date of the revision is fairly early (February 2017).
Since javac
generates the correct method signature, you could switch to that for the time being as a workaround.
7
I tend to over-complicate these bytecode related answers (being someone who's used to looking at bytecode). It's hard to find the right balance between sufficient explanation, and keeping the answer succinct. If anything is unclear, please feel free to ask for clarification.
– Jorn Vernee
yesterday
this is not over-complicate and it's an easy to read and understand answer, there simply isn't a better one. I had a pleasure reading it, thank you for taking the time
– Eugene
yesterday
Could you please add a link to the corresponding Eclipse bug?
– howlger
yesterday
@JornVernee Not at all. I think you explain bytecode related answers very well.
– Michael Berry
yesterday
2
@howlger Done: bugs.eclipse.org/bugs/show_bug.cgi?id=546161
– Jorn Vernee
yesterday
|
show 5 more comments
TL;DR The Eclipse compiler generates a method signature for the lambda instance that is invalid according to the specification. Due to additional type checking code added in JDK 9 to better enforce the specification, the incorrect signature is now causing an exception when running on Java 11.
Verified with Eclipse 2019-03 as well with this code:
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);
}
Even when using null
as the receiver, the code fails when bootstrapping with the same error.
Using javap -v Main
we can see where the problem lies. I'm seeing this in the BoostrapMethods table:
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
Note that the last argument (constant #54) is (Ljava/lang/Object;)V
, while javac
generates (Lmain/HasValue$ValueChangeEvent;)V
. i.e. the method signature that Eclipse wants to use for the lambda is different from what javac
wants to use.
If the wanted method signature is the erasure of the target method (which seems to be the case), then the correct method signature is indeed (Lmain/HasValue$ValueChangeEvent;)V
since that is the erasure of the target method, which is:
void valueChanged(E event);
Where E
is E extends HasValue.ValueChangeEvent<?>
, so that would be erased to HasValue.ValueChangeEvent
.
The problem seems to be with ECJ, and seems to have been brought to the surface by JDK-8173587 (revision) (Unfortunately this seems to be a private ticket.) which adds extra type checks to verify that the SAM method type is actually compatible with the instantiate method type. According to the documentation of LambdaMetafactory::metafactory
the instantiated method type must be the same, or a specialization of the SAM method type:
instantiatedMethodType - The signature and return type that should be enforced dynamically at invocation time. This may be the same as samMethodType, or may be a specialization of it.
which the method type generated by ECJ is evidently not, so this ends up throwing an exception. (though, to be fair, I don't see defined anywhere what constitutes a "specialization" in this case). I've reported this on the Eclipse bugzilla here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=546161
I'm guessing this change was made somewhere in JDK 9, since source code was already modular at that point, and the date of the revision is fairly early (February 2017).
Since javac
generates the correct method signature, you could switch to that for the time being as a workaround.
TL;DR The Eclipse compiler generates a method signature for the lambda instance that is invalid according to the specification. Due to additional type checking code added in JDK 9 to better enforce the specification, the incorrect signature is now causing an exception when running on Java 11.
Verified with Eclipse 2019-03 as well with this code:
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);
}
Even when using null
as the receiver, the code fails when bootstrapping with the same error.
Using javap -v Main
we can see where the problem lies. I'm seeing this in the BoostrapMethods table:
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
Note that the last argument (constant #54) is (Ljava/lang/Object;)V
, while javac
generates (Lmain/HasValue$ValueChangeEvent;)V
. i.e. the method signature that Eclipse wants to use for the lambda is different from what javac
wants to use.
If the wanted method signature is the erasure of the target method (which seems to be the case), then the correct method signature is indeed (Lmain/HasValue$ValueChangeEvent;)V
since that is the erasure of the target method, which is:
void valueChanged(E event);
Where E
is E extends HasValue.ValueChangeEvent<?>
, so that would be erased to HasValue.ValueChangeEvent
.
The problem seems to be with ECJ, and seems to have been brought to the surface by JDK-8173587 (revision) (Unfortunately this seems to be a private ticket.) which adds extra type checks to verify that the SAM method type is actually compatible with the instantiate method type. According to the documentation of LambdaMetafactory::metafactory
the instantiated method type must be the same, or a specialization of the SAM method type:
instantiatedMethodType - The signature and return type that should be enforced dynamically at invocation time. This may be the same as samMethodType, or may be a specialization of it.
which the method type generated by ECJ is evidently not, so this ends up throwing an exception. (though, to be fair, I don't see defined anywhere what constitutes a "specialization" in this case). I've reported this on the Eclipse bugzilla here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=546161
I'm guessing this change was made somewhere in JDK 9, since source code was already modular at that point, and the date of the revision is fairly early (February 2017).
Since javac
generates the correct method signature, you could switch to that for the time being as a workaround.
edited yesterday
answered yesterday
Jorn VerneeJorn Vernee
21.3k34266
21.3k34266
7
I tend to over-complicate these bytecode related answers (being someone who's used to looking at bytecode). It's hard to find the right balance between sufficient explanation, and keeping the answer succinct. If anything is unclear, please feel free to ask for clarification.
– Jorn Vernee
yesterday
this is not over-complicate and it's an easy to read and understand answer, there simply isn't a better one. I had a pleasure reading it, thank you for taking the time
– Eugene
yesterday
Could you please add a link to the corresponding Eclipse bug?
– howlger
yesterday
@JornVernee Not at all. I think you explain bytecode related answers very well.
– Michael Berry
yesterday
2
@howlger Done: bugs.eclipse.org/bugs/show_bug.cgi?id=546161
– Jorn Vernee
yesterday
|
show 5 more comments
7
I tend to over-complicate these bytecode related answers (being someone who's used to looking at bytecode). It's hard to find the right balance between sufficient explanation, and keeping the answer succinct. If anything is unclear, please feel free to ask for clarification.
– Jorn Vernee
yesterday
this is not over-complicate and it's an easy to read and understand answer, there simply isn't a better one. I had a pleasure reading it, thank you for taking the time
– Eugene
yesterday
Could you please add a link to the corresponding Eclipse bug?
– howlger
yesterday
@JornVernee Not at all. I think you explain bytecode related answers very well.
– Michael Berry
yesterday
2
@howlger Done: bugs.eclipse.org/bugs/show_bug.cgi?id=546161
– Jorn Vernee
yesterday
7
7
I tend to over-complicate these bytecode related answers (being someone who's used to looking at bytecode). It's hard to find the right balance between sufficient explanation, and keeping the answer succinct. If anything is unclear, please feel free to ask for clarification.
– Jorn Vernee
yesterday
I tend to over-complicate these bytecode related answers (being someone who's used to looking at bytecode). It's hard to find the right balance between sufficient explanation, and keeping the answer succinct. If anything is unclear, please feel free to ask for clarification.
– Jorn Vernee
yesterday
this is not over-complicate and it's an easy to read and understand answer, there simply isn't a better one. I had a pleasure reading it, thank you for taking the time
– Eugene
yesterday
this is not over-complicate and it's an easy to read and understand answer, there simply isn't a better one. I had a pleasure reading it, thank you for taking the time
– Eugene
yesterday
Could you please add a link to the corresponding Eclipse bug?
– howlger
yesterday
Could you please add a link to the corresponding Eclipse bug?
– howlger
yesterday
@JornVernee Not at all. I think you explain bytecode related answers very well.
– Michael Berry
yesterday
@JornVernee Not at all. I think you explain bytecode related answers very well.
– Michael Berry
yesterday
2
2
@howlger Done: bugs.eclipse.org/bugs/show_bug.cgi?id=546161
– Jorn Vernee
yesterday
@howlger Done: bugs.eclipse.org/bugs/show_bug.cgi?id=546161
– Jorn Vernee
yesterday
|
show 5 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55532055%2fjava-casting-java-11-throws-lambdaconversionexception-while-1-8-does-not%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Interesting and yet poor thing there
(HasValue<?,?>) comp
... Such validation though agreed didn't exist in the JDK-8 code.– Naman
yesterday
When exactly do you get this exception? When you add the listener or when the listener is invoked with an event? If the latter, how do you invoke it with an event (show the code place)
– Erwin Bolwidt
yesterday
8
That’s an important information, as Eclipse has its own compiler, so problems caused by the compiler (and this looks much like a compiler problem) do not have to apply to
javac
then.– Holger
yesterday
2
@JornVernee changing the language level sometimes causes behavioral changes in the compiler.
– Holger
yesterday
1
@CommonMan IJ neither has its own compiler nor is it a Java VM, so it makes no difference in this case whether you write your code with IJ or a text editor.
– howlger
yesterday