I have the following class, which represents an entity that can be identified by a String
id:
public abstract class IdentifiableEntity {
private String id;
// getters & setters
}
Then, I have the following interface, which represents an object that can be filled with data coming from the argument:
public interface Fillable<T> {
void fill(T full);
}
Fillable
objects are always filled with full copies of the same class, i.e. a Fillable
Person
would be used this way:
public class Person implements Fillable<Person> {
// attributes, getters & setters
public void fill(Person full) {
// deeply copy data from full person to this person
}
}
Finally, I have the following interface, whose default method receives a stream of objects that are both IdentifiableEntity
and Fillable
, and an empty object that is also IdentifiableEntity
and Fillable
:
public interface Hydrator {
default <T extends IdentifiableEntity & Fillable<T>> void searchAndFill(
Stream<T> stream, T empty) {
stream
.filter(p -> p.getId().equals(empty.getId()))
.findAny()
.ifPresent(e -> empty.fill(e));
}
}
The above code both compiles and works fine. It searches an element from the stream by id and uses it to fill the empty object.
However, when I change the final lambda expression to its equivalent method reference:
stream
.filter(p -> p.getId().equals(empty.getId()))
.findAny()
.ifPresent(empty::fill);
This compiles fine, but fails with the following runtime exception:
java.lang.invoke.LambdaConversionException: Invalid receiver type class IdentifiableEntity; not a subtype of implementation type interface Fillable
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
... 55 common frames omitted
JDK version is "1.8.0_65"
.