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
In TypeBasedCandidateFilter.isCompatibleTypes -> ClassCastException: class TypeVariableImpl cannot be cast to class Class #3294
Comments
After a closer look and local playing around with the code the feature "support generics" #2923 released with v5.2.0 introduced the problems which several users have reported. Now that more and more projects will have to upgrade their dependency to the latest mockito to have JDK 21 support more will arrive at this situation of being blocked by this "broken" behaviour in Mockito in comparison to before 5.2.0. If you agree with such approach, how would you define such a feature toggle/option? Where is the best "place" for it for the user? What would you usually prefer? |
Sorry I haven't been looking at issues lately, what other issues pointing to a bug in that feature would come to your mind? If there was a sudden wave of related issues due to JDK LTS changes, with a variety of different exceptions, then IMHO a feature toggle would be good. On the other hand, if it is only the same or very few underlying cases, we better fix those :) |
It is more a feeling when reading release notes and other issues that this feature has yet not reached full "maturity" for all cases. Of course, fixing the different cases is an option and I would be happy to assist that. I will fork and commit my play around version of the TypeBaseCandidateFilter now so that you could see some places which might need some workover. Update: |
…class TypeVariableImpl cannot be cast to class Class mockito#3294 Playing around to minimize errors in tests: - checked with "instanceof" to avoid class cast exception - sysouts for some "simple tracing" - widened comparison from TypeVariable#equals to allow "super types" in generic declaration as it seemed right to me
During lunch break I have tried out to introduce such a simple feature toggle via System property in org.mockito.internal.configuration.injection.filter.TypeBasedCandidateFilter.filterCandidate(Collection, Field, List, Object, Field) So either just switching on that old behaviour in that single place is not enough "rollback" or there is another problem which I don't know the location yet... |
…class TypeVariableImpl cannot be cast to class Class mockito#3294 introduced simple system property based feature toggle to disable "generics support" e.g. pass "-Dmockito.typeBasedCandidateFilter.genericsSupport.disabled" to surefire/tycho-surefire maven plugin to disable it generics support is still switched on per default
…class TypeVariableImpl cannot be cast to class Class mockito#3294 added test case to verify first case of mockito#3294: generics in combintation with inheritance in test and under test classes led to a ClassCastException (java.lang.ClassCastException: class sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to class java.lang.Class (sun.reflect.generics.reflectiveObjects.TypeVariableImpl and java.lang.Class are in module java.base of loader 'bootstrap') at org.mockito.internal.configuration.injection.filter.TypeBasedCandidateFilter.isCompatibleTypes(TypeBasedCandidateFilter.java:64))
Looking at the rest of the failing tests in our project I think we are in many cases hit by the behaviour change #2978 / #2603
I assume we are out of luck here and that the official recommendation is to either provide a constructor with all parameters to be mocked or to use setter / field injection (remove any constructor with parameter)... Actually we were quite used to the "combined injection" behaviour and it worked well for us and currently I don't get what was so bad about it. |
…class TypeVariableImpl cannot be cast to class Class mockito#3294 - just ignore Object typed fields during injection target analysis, because it will almost always lead to unwanted "multiple matches" problem - moved knowledge about feature toggle GENERICS_SUPPORT_DISABLED_KEY back to TypeBasedCandidateFilter private scope and printing it just once
…class TypeVariableImpl cannot be cast to class Class mockito#3294 introduced simple feature toggle via system property "mockito.constructorInjection.alwaysTryNextStrategy.enabled" to in effect pass injection on to PropertyAndSetterInjection to optionally "restore" a bit of the pre 5.2.0 behaviour. Per default this legacy behaviour is turned off.
Now test cases of that one project back to green. Achieved this by changing code back towards the legacy pre-5.2.0 behaviour. |
Based on my understanding of the various issues that have popped up after 5.2.0, the We have had several proposals from community members to resolve this issue and I reviewed all PRs with suggestions. The most dedicated effort was in #3123 which is also a massive PR introducing more than 1500 new lines of code. Unfortunately we cannot make such massive overhaul and complications into our system, as users also rely on the performance and ease of mocks. Therefore, I do think that we now align with what we originally promised. But the frustrating bit for users is that they have grown used to the previous behavior. Whether the previous behavior is better or not is a subjective question that truthfully, I don't know the answer to. If you do have any suggestions on how we can improve the status quo while also ensure we maintain existing behavior and have minimal impact on the overall system, please send us a PR. One thing that I do want to make explicit: we will not introduce runtime flags for changing Mockito behavior. This has been suggested multiple times (not just for |
Thanks a lot for your reply and insights it provides to us externals ;) So about
I think what could help here is to make more mechanisms of Mockito exchangeable like JUnit 5 vs JUnit 4 or Eclipse E4 vs E3. I would see one important extension/variation point which probably would help a lot of pre-5.2.0 projects/users like us (relying on "do some more injection like in the 'old days'") to configure Mockito to their own needs: Let me for example tell you why we need/rely on that "constructor plus field injection" mechanism: So far I have only scratched the surface of Mockito code and just checked quickly if I could make that injection engine exchangeable. Probably you insiders know best where to create such extension resp. if it is at all feasible. |
Luckily that was my suggestion as well on the linked PR: #3123 (comment) As you can see in the PR, it introduces a new If you can help us revive that PR and make it ready for merging (based on the feedback I gave on it), that would be amazing 😄 |
…class TypeVariableImpl cannot be cast to class Class mockito#3294 - "inverted" and renamed feature toggles to have them active per default which is the pre 5.2.0 behaviour more or less - to have unchanged tests still runnable, set the feature toggles to enable "new", unwanted behaviour
Problem description
Given:
We are currenty migration from mocktio 5.1 and JDK 17 to mockito 5.11 and JDK 21.
We use annotation based mock injection.
Versions:
Mockito 5.11.0
Junit Jupiter 5.10.1
OpenJDK 64-Bit Server VM Temurin-21.0.2+13 (build 21.0.2+13-LTS, mixed mode, sharing)
Maven 3.9.6
Eclipse IDE 2023-12
Problematic scenario
Our problematic test case(s) extend a base test class with a type parameter
BaseTest<T>
This base test class also contains a field using the type variable
When:
When the test is executed, either by Maven or via Eclipse IDE directly
Then
errors occur, the following stack trace can be seen
During debugging the type variable 'T' is seen which is not "instanceof Class" but "instanceof Type".
This finally provokes the ClassCastException.
See next section for affected code; I assume another case is missing here: either it is a parameterized type or a non-parameterized type or none of those two.
Affected code*
in org.mockito.internal.configuration.injection.filter.TypeBasedCandidateFilter.isCompatibleTypes(Type, Type, Field)
So any info/help is welcome to fix this problem!
Attached maven project can be run with 5.1 and JDK 17 (working) or with 5.11 (not working).
reproduce_3294.zip
colleague mentioned that #2958 resp. #3019 is probably related...
The text was updated successfully, but these errors were encountered: