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
HV-840 [follow-up] Annotation Processor doesn't detect errors in parameter constraints in inheritance hierarchies #584
Conversation
…ch goes through classes and checks all methods if they are correctly overridden
…cted how annotations mirrors are compared.
…ds inheritance tree.
collectOverriddenMethodsInInterfaces( overriddenMethod, interfaceTypeElement, methodInheritanceTreeBuilder ); | ||
} | ||
else { | ||
collectOverriddenMethodsInInterfaces( overridingMethod, interfaceTypeElement, methodInheritanceTreeBuilder ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks that collectOverriddenMethodsInInterfaces
can be moved out of if else as it is called in both cases ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a slight difference in the calls: one is using overriddenMethod
and the other overridingMethod
. I thought it was clearer this way than to declare another variable. Your question makes me think I might be wrong. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I fixed it, it seems to be clearer now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahhaa ! when I was looking at it these two lines looked the same to me :)
if ( !element.getKind().equals( ElementKind.METHOD ) ) { | ||
continue; | ||
} | ||
if ( elementUtils.overrides( currentMethod, (ExecutableElement) element, currentTypeElement ) ) { | ||
if ( elementUtils.overrides( currentMethod, (ExecutableElement) element, getEnclosingTypeElement( currentMethod ) ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe get enclosing element before the loop ? or this operation is not very expensive ? Something like:
TypeElement methodEnclosingType = getEnclosingTypeElement( currentMethod );
for (...){
....
if ( elementUtils.overrides( currentMethod, (ExecutableElement) element, methodEnclosingType ) ) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right! I'll fix it, thanks for noticing.
* </p> | ||
* | ||
* @author Marko Bekhta | ||
*/ | ||
public abstract class AbstractClassCheck implements ClassCheck { | ||
|
||
@Override | ||
public Collection<ConstraintCheckIssue> checkMethod(ExecutableElement element) { | ||
public Set<ConstraintCheckIssue> checkMethod(ExecutableElement element) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just out of interest - did you changed to Set to be more consistent with the existing checks or is there any other reasons ? I was thinking that if we are not using any Set specific behavior a more general collection interface can be used (that's just an explanation why I used Collection in the first place)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's just for the sake of consistency. I must admit I wouldn't have changed it if I didn't have other changes to do.
To be honest, if I had to do it from the ground up, I think I would have used ArrayList everywhere to have the result as predictable as possible. I don't think Sets are of much value here.
hi @gsmet ! All looks great ! You definitely are much better at naming methods and variables :) and a great improvement to MethodInheritanceTree as well. Also I can see that it seems like I still need to do some changes to my IDE formatting as there still are some differences :) As for the delays - it's all fine and I completely understand it. I myself got stuck with my work and wasn't able to spent much time on HV related items :) Have a nice day, |
@marko-bekhta thanks for the review. I pushed a commit fixing your remarks. Is it better now? (I'll probably squash it before merging) |
@gsmet yes ! looks great ! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gsmet I looked mainly at the tests, not the impl so much. The expected behavior in the tests look right. Two comments inline.
); | ||
|
||
assertEquals( diagnostics.getDiagnostics().get( 0 ).getMessage( Locale.getDefault() ), | ||
"Parameters of method \"doSomething((@javax.validation.constraints.NotNull :: java.lang.String))\" do not respect the inheritance rules. " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error will be shown in the context of the method. Do we need to repeat the entire signature? Shouldn't the compiler itself point it out?
public static class MethodOverridingTestCase2Sub extends MethodOverridingTestCase2 { | ||
|
||
@Override | ||
public void doSomething(@NotNull @NotBlank @Size(max = 10) String param) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a strong need to check for this? Technically, it doesn't represent any constraint strengthening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it does not respect the inheritance rules we defined. The rule is that you cannot define constraints in the method hierarchy if there are already one method defining constraints in the method hierarchy. That's what we implemented here.
And it's definitely easier to throw an error for this than trying to determine what is or what is not a constraint strengthening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At runtime, we'd allow that one. See OverridingMethodMustNotAlterParameterConstraints
and how it's calling !method.isEquallyParameterConstrained()
. That's primarily due to the behavior of Weld proxy classes though which would copy the annotations from proxied classes verbatim to the method definition on the proxy.
I'd prefer behavior of the AP to closely mimic the runtime engine, but if it's too cumbersome to do, we can leave as you've proposed it. It's in the sense of the spec for sure.
import org.hibernate.validator.ap.util.MessagerAdapter; | ||
|
||
/** | ||
* An abstract {@link javax.lang.model.element.ElementVisitor} that should be used for implementation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No biggie, but we can use simple names in JavaDocs (and import them), too. Reads a tad nicer.
@marko-bekhta ... and merged! Thanks for your tenacity on this subject, we finally got this in! |
@gsmet Great ! :) |
Hi @marko-bekhta ,
So I did a couple of fixes and thought we might as well start with a clean review slate instead of having dozens of comments piling up.
This is all based on what you did. As you suspected it, the inheritance tree was what I had in mind. I fixed a couple of issues though, the most important one being that you ended the exploration when a superclass did not have the method, while you should also have explored the superclasses of this superclass.
I think we now have something working pretty well.
Sorry again about the delay, we had a few bad surprises with our upgrade in WildFly our it drained a lot of time and efforts.
Comments welcome!
--
Guillaume