-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhancement: make Java8 lambda steps reflection portable and use stable javac APIs #937
Comments
OK, here's what I have been able to find. Statement of ProblemWe want to be able to write steps like:
The step definitions are stored as instances of Therefore, we need to be able to determine the full generic parameter type of each Lambda method argument. Java 8 does not make this info available at runtime via reflection (see detailed comments on #936). Possible fixes:
Each is described below: Remove this impossible requirement by making the API more repetitiveIt looks like targeting the above API for Cucumber will cause ongoing issues (see "cons" below).
Pros:
Cons:
Use the
|
Actually, now that I've written all this out, option 4, "Leave all this alone, stick to inspecting the class constant pool" is looking increasingly attractive :-) |
Hi @RichardBradley thanks for that very detailed analysis! For starters I think we should add an additional API as described in option 1. It could be in The original API could maybe delegate to this API to avoid too much duplication. We could also try to improve the original API by pursuing the constant pool route. So to sum up:
WDYT? |
Good plan -- I like it. Adding a What do you mean by "Improve original constant pool API using the proposed hacks"? Are you talking about this commit 046d98c ? I think you should get that commit onto |
Please don't use Lombok's magic under the hood - it leads to undefined unstable behviour. It may conflict with another generators like Mapstruct (eg. github.com/mapstruct/mapstruct/issues/510). |
The way I'm proposing to use Lombok to rewrite method bodies wouldn't cause conflicts like that in the issue you linked to.
As explained above, the annotation processing API isn't powerful enough to solve this case for us (doesn't allow inspection or modification of method bodies). I don't think runtime code generation is applicable here. I think we should probably stick to the current constant pool reflector (i.e. option 4). We should still do option 1 to make all this more explicit and pluggable though. |
For the record, I'm not planning to do anything further on this thread, since option 4 ("Leave all this alone, stick to inspecting the class constant pool") looks to be the best, given the serious problems with the other options. |
I am sharing the opinion of @RichardBradley and I would like to suggest replacing our current implementation with an existing one. TypeTools is a minimal light weight library that does everything our ConstantPoolInspector does and does it much better. I'll tackle this in #1178. |
To determine which argument types a lambda function requires we created a ConstantPoolTypeIntrospector. However it has never functioned quite correctly (#937, #1140, #957), was prone to breaking (#912, #914) and hasn't been tested much (#1048). It is important to understand that while we will get a properly functioning and tested replacement, TypeResolver uses the same ConstantPool and thus has the same potential to break. However because TypeResolver is used by a much larger audience I expect these problems to be shallow. Because this change the interface of Java8StepDefinition it made sense to refactor all the Java8 related stuff out of cucumber-java. This will make it easier in the future to add things like KotlinStepDefintions without creating a separate KotlinBackend. Related issues: - #912 - #914 - #937 - #957 - #1140 - #1048 - #1140 -
To determine which argument types a lambda function requires we created a ConstantPoolTypeIntrospector. However it has never functioned quite correctly (#937, #1140, #957), was prone to breaking (#912, #914) and hasn't been tested much (#1048). It is important to understand that while we will get a properly functioning and tested replacement, TypeResolver uses the same ConstantPool and thus has the same potential to break. However because TypeResolver is used by a much larger audience I expect these problems to be shallow. Because this change the interface of Java8StepDefinition it made sense to refactor all the Java8 related stuff out of cucumber-java. This will make it easier in the future to add things like KotlinStepDefintions without creating a separate KotlinBackend. Related issues: - #912 - #914 - #937 - #957 - #1140 - #1048 - #1140
To determine which argument types a lambda function requires we created a ConstantPoolTypeIntrospector. However it has never functioned quite correctly (#937, #1140, #957), was prone to breaking (#912, #914) and hasn't been tested much (#1048). It is important to understand that while we will get a properly functioning and tested replacement, TypeResolver uses the same ConstantPool and thus has the same potential to break. However because TypeResolver is used by a much larger audience I expect these problems to be shallow. Because this change the interface of Java8StepDefinition it made sense to refactor all the Java8 related stuff out of cucumber-java. This will make it easier in the future to add things like KotlinStepDefintions without creating a separate KotlinBackend. Related issues: - #912 - #914 - #937 - #957 - #1140 - #1048 - #1140
To determine which argument types a lambda function requires we created a ConstantPoolTypeIntrospector. However it has never functioned quite correctly (#937, #1140, #957), was prone to breaking (#912, #914) and hasn't been tested much (#1048). It is important to understand that while we will get a properly functioning and tested replacement, TypeResolver uses the same ConstantPool and thus has the same potential to break. However because TypeResolver is used by a much larger audience I expect these problems to be shallow. Because this change the interface of Java8StepDefinition it made sense to refactor all the Java8 related stuff out of cucumber-java. This will make it easier in the future to add things like KotlinStepDefintions without creating a separate KotlinBackend. Related issues: - #912 - #914 - #937 - #957 - #1140 - #1048 - #1140 Closes #937
To determine which argument types a lambda function requires we created a ConstantPoolTypeIntrospector. However it has never functioned quite correctly (#937, #1140, #957), was prone to breaking (#912, #914) and hasn't been tested much (#1048). It is important to understand that while we will get a properly functioning and tested replacement, TypeResolver uses the same ConstantPool and thus has the same potential to break. However because TypeResolver is used by a much larger audience I expect these problems to be shallow. Because this change the interface of Java8StepDefinition it made sense to refactor all the Java8 related stuff out of cucumber-java. This will make it easier in the future to add things like KotlinStepDefintions without creating a separate KotlinBackend. Related issues: - #912 - #914 - #937 - #957 - #1140 - #1048 - #1140 Closes #937 Closes #1048
To determine which argument types a lambda function requires we created a ConstantPoolTypeIntrospector. However it has never functioned quite correctly (#937, #1140, #957), was prone to breaking (#912, #914) and hasn't been tested much (#1048). It is important to understand that while we will get a properly functioning and tested replacement, TypeResolver uses the same ConstantPool and thus has the same potential to break. However because TypeResolver is used by a much larger audience I expect these problems to be shallow. Because this change the interface of Java8StepDefinition it made sense to refactor all the Java8 related stuff out of cucumber-java. This will make it easier in the future to add things like KotlinStepDefintions without creating a separate KotlinBackend. Related issues: - #912 - #914 - #937 - #957 - #1140 - #1048 - #1140 Closes #937 Closes #1048
Love it, great work! |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
See:
Currently, for Java8 lambda steps to work, the step runner needs to know the declared type of all arguments to the step body (see
Java8StepDefinition.getParameterInfos
).The declared type can be any runtime type, including primitives like
int
, normal classes likeString
or generic types likeList<String>
. Users can register converters to allow any type for these step params (seecucumber.runtime.ParameterInfo.convert
), including perhapsObject
(although that would be a pathological case, I expect it might need special handling by the reflector and it does seem to be allowed).It does look to me like we could replace the class ConstantPool inspector with a compile-time Compiler Annotation Processor which records the declared generic types.
See e.g. http://stackoverflow.com/questions/29922668/get-typeelement-from-generic-typeparameterelement-for-java-annotation-processor
This would mean that cucumber-jvm would be using a public supported javac API, instead of hacking about with trying to interpret the class files internals (which might change again).
We could either require Cucumber java8 users to annotate their Step files to give cucumber-jvm access to edit the source, or we could do a full project lombok and register a compiler plugin for everyone who compiles anything with cucumber-java8 on the classpath and scan for (and fixup) all calls to En.Given etc.
I'll see if I can get this to work and submit a POC.
This will need careful testing, and possibly deserve a major release version, as it will greatly change how
java8
steps are compiled.We'll need to test different compilers and different build tools (Maven, ant, manual javac) and check that they all execute the CAP correctly.
First though, I'll write a proof of concept to see if this can be made to work at all, and what the code would look like with this new approach.
The text was updated successfully, but these errors were encountered: