4

I have a unit test that searches through my project and finds all implementations of a particular interface. Then for each implementation that is an inner class, I assert that it does not capture the outer class.

I use the Reflections library to do this, and it did work, but now I need to test another interface, many of whose implementations are lambdas. Sadly, Reflections cannot find lambda implementations of interfaces.

Is there another solution I can use that will work with lambdas?

whistling_marmot
  • 3,561
  • 3
  • 25
  • 39
  • Requests for library recommendations are off-topic here. – John Bollinger Nov 07 '17 at 14:51
  • 2
    You can use a bytecode processing library like ASM to write a tool that finds all lambda creation sites, but determining whether they capture the outer `this` instance is tricky, as the mere presence of a captured reference of that type doesn't have to be `this`; it could be a deliberately captured variable of the same type instead.Also, I suppose you only care for accidental capturing, so explicit constructs like `this::method` should not count... – Holger Nov 07 '17 at 16:35

1 Answers1

4

Reflections cannot find lambda implementations of interfaces. Is there another solution I can use that will work with lambdas?

There is no reliable approach to identify instances of functional interfaces using reflection, and it doesn't look like there ever will be. See this response to an openjdk request to Introduce a compiler option to store generic type information about a lambda expression using the Signature Attribute:

I get why people want reflection to work over lambda instances, but that's not how reflection works -- reflection reflects over classes, not instances. The current translation strategy happens to be one that, were this attribute there, would enable reflection to "accidentally work" to provide generic information, but this will change, at which point any reflection-based strategy falls apart (at which point people accuse of breaking their should-have-never-worked-in-the-first-place code.)

In a similar vein, see these comments (also from Brian Goetz) in this SO post Why are Java 8 lambdas invoked using invokedynamic?

The runtime implementation is free to select a strategy dynamically to evaluate the lambda expression. The runtime implementation choice is hidden behind a standardized (i.e., part of the platform specification) API for lambda construction, so that the static compiler can emit calls to this API, and JRE implementations can choose their preferred implementation strategy.

The bottom line is that you can't know how your lambda expressions will be processed at run time.

skomisa
  • 16,436
  • 7
  • 61
  • 102
  • 2
    This is missing the point. The cited mail is about wishes to get the generic type information of lambda instances, which has nothing to do with this question. Whereas the cited Q&A only tells that you can’t locate the interface implementation class, as it’s JRE specific, however, that doesn’t preclude finding the `invokedynamic` instructions, which already tell you, which interface will be implemented and which values it has to capture. You don’t need to know how it does it… – Holger Nov 08 '17 at 07:33