question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Lambda expressions for generic target types

See original GitHub issue

I am using InvokeDynamic.lambda(InDefinedShape, TypeDescription) to create the equivalent of these two methods:

    static interface StringMeasure
    {
        Integer measure(String string);
    }
    
    StringMeasure stringMeasure()
    {
        return String::length;
    }

    Function<String, Integer> stringLengthFunction()
    {
        return String::length;
    }

This works as expected for the stringMeasure() method, but I’m having a hard time getting Byte Buddy to generate correct code for the stringLengthFunction() method. So far, my efforts have yielded NoSuchMethodErrors, AbstractMethodErrors, or LambdaConversionException: Invalid receiver type.

I noticed that there is a slight difference in the bootstrap methods generated for the two cases. For stringMeasure() the Java compiler produces the following:

  fava.tests.ByteBuddyTest$StringMeasure stringMeasure();
    Code:
       0: invokedynamic #16,  0             // InvokeDynamic #0:measure:()Lfava/tests/ByteBuddyTest$StringMeasure;
       5: areturn

...

BootstrapMethods:
  0: #38 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:
      #40 (Ljava/lang/String;)Ljava/lang/Integer;
      #47 REF_invokeVirtual java/lang/String.length:()I
      #48 (Ljava/lang/String;)Ljava/lang/Integer;

For the other method, the Java compiler’s output looks a little different:

  java.util.function.Function<java.lang.String, java.lang.Integer> stringLengthFunction();
    Code:
       0: invokedynamic #23,  0             // InvokeDynamic #1:apply:()Ljava/util/function/Function;
       5: areturn

...

  1: #38 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 (Ljava/lang/Object;)Ljava/lang/Object;
      #51 REF_invokeVirtual java/lang/String.length:()I
      #52 (Ljava/lang/String;)Ljava/lang/Integer;

The difference is the first argument to the bootstrap method: when targeting the (non-parameterized) StringMeasure interface we see the input and output types as expected: (Ljava/lang/String;)Ljava/lang/Integer;. When targeting the java.util.function.Function interface, the first argument corresponds to the type erasure of the interface, i.e., (Ljava/lang/Object;)Ljava/lang/Object;, whereas the third argument appears to be the fully reified signature.

Both of these examples were collected from the output of the Java compiler. I can generate the code for the first example in Byte Buddy, but the second example is giving me trouble: I end up with (Ljava/lang/Object;)Ljava/lang/Object; for both the first and the third bootstrap method argument. This even makes somewhat sense: the method description is passed as a MethodDescription.InDefinedShape, which does not resolve type variables, and the functional interface type is passed as a TypeDescription, which again can only represent non-generic types.

It seems to me that one would need the capability to pass the functional interface as a Generic type, to address this case. Is this a current limitation of Byte Buddy, or is there a different way to generate lambda expressions for generic interfaces?

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
raphwcommented, Sep 21, 2021

This week, I think.

0reactions
ranercommented, Sep 21, 2021

Will there be another Byte Buddy release this month? I’m just curious when I can expect this to be available in Maven Central. Thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

java - Lambda Expression and generic defined only in method
A lambda expression is compatible [..] with a target type T if T is a functional interface type (§9.8) and the expression is...
Read more >
Lambda expressions for generic functional interfaces. Examples
The functional interface can be generic (template). In this case, the target type of the lambda expression is determined based on the type...
Read more >
Generalized Target-Type Inference in Java - Baeldung
Explore Java's Type Inference, that along with generics and Lambda Expression enables us to write concise Java code.
Read more >
What is the generic functional interface in Java? - Tutorialspoint
A lambda expression can't specify type parameters, so it's not generic. However, a functional interface associated with lambda expression is ...
Read more >
Lambda Expressions (The Java™ Tutorials > Learning the ...
To determine the type of a lambda expression, the Java compiler uses the target type of the context or situation in which the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found