-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Reimplement EnclosedElementsQuery
to improve performance
#10237
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,6 +51,7 @@ | |
import io.micronaut.inject.ast.utils.AstBeanPropertiesUtils; | ||
import io.micronaut.inject.ast.utils.EnclosedElementsQuery; | ||
import org.codehaus.groovy.ast.AnnotatedNode; | ||
import org.codehaus.groovy.ast.AnnotationNode; | ||
import org.codehaus.groovy.ast.ClassHelper; | ||
import org.codehaus.groovy.ast.ClassNode; | ||
import org.codehaus.groovy.ast.ConstructorNode; | ||
|
@@ -720,21 +721,25 @@ protected Collection<ClassNode> getInterfaces(ClassNode classNode) { | |
|
||
@Override | ||
protected List<AnnotatedNode> getEnclosedElements(ClassNode classNode, | ||
ElementQuery.Result<?> result) { | ||
ElementQuery.Result<?> result, | ||
boolean includeAbstract) { | ||
Class<?> elementType = result.getElementType(); | ||
return getEnclosedElements(classNode, result, elementType); | ||
return getEnclosedElements(classNode, result, elementType, includeAbstract); | ||
} | ||
|
||
private List<AnnotatedNode> getEnclosedElements(ClassNode classNode, ElementQuery.Result<?> result, Class<?> elementType) { | ||
private List<AnnotatedNode> getEnclosedElements(ClassNode classNode, | ||
ElementQuery.Result<?> result, | ||
Class<?> elementType, | ||
boolean includeAbstract) { | ||
if (elementType == MemberElement.class) { | ||
return Stream.concat( | ||
getEnclosedElements(classNode, result, FieldElement.class).stream(), | ||
getEnclosedElements(classNode, result, MethodElement.class).stream() | ||
getEnclosedElements(classNode, result, FieldElement.class, includeAbstract).stream(), | ||
getEnclosedElements(classNode, result, MethodElement.class, includeAbstract).stream() | ||
).toList(); | ||
} else if (elementType == MethodElement.class) { | ||
return classNode.getMethods() | ||
.stream() | ||
.filter(methodNode -> !JUNK_METHOD_FILTER.test(methodNode) && (methodNode.getModifiers() & Opcodes.ACC_SYNTHETIC) == 0) | ||
.filter(methodNode -> !JUNK_METHOD_FILTER.test(methodNode) && (methodNode.getModifiers() & Opcodes.ACC_SYNTHETIC) == 0 && (includeAbstract || isNonAbstract(classNode, methodNode))) | ||
.<AnnotatedNode>map(m -> m) | ||
.toList(); | ||
} else if (elementType == FieldElement.class) { | ||
|
@@ -761,6 +766,19 @@ private List<AnnotatedNode> getEnclosedElements(ClassNode classNode, ElementQuer | |
} | ||
} | ||
|
||
private boolean isNonAbstract(ClassNode classNode, MethodNode methodNode) { | ||
if (methodNode.isDefault()) { | ||
return false; | ||
} | ||
if (methodNode.isPrivate() && classNode.isInterface()) { | ||
return false; | ||
} | ||
if (!methodNode.isAbstract() && classNode.isInterface()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i dont understand this method. private & interface -> abstract? !abstract & interface -> abstract? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. private methods are never abstract, and the other one is the default method There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this code says that private interface methods are abstract though There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I see, fixed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can drop the interface check too i guess |
||
return false; | ||
} | ||
return !methodNode.isAbstract(); | ||
} | ||
|
||
@Override | ||
protected boolean excludeClass(ClassNode classNode) { | ||
String packageName = Objects.requireNonNullElse(classNode.getPackageName(), ""); | ||
|
@@ -775,6 +793,23 @@ protected boolean excludeClass(ClassNode classNode) { | |
|| Script.class.getName().equals(className); | ||
} | ||
|
||
@Override | ||
protected boolean isAbstractClass(ClassNode classNode) { | ||
return classNode.isAbstract(); | ||
} | ||
|
||
@Override | ||
protected boolean isInterface(ClassNode classNode) { | ||
if (classNode.isInterface()) { | ||
return true; | ||
} | ||
List<AnnotationNode> annotations = classNode.getAnnotations(); | ||
if (annotations != null) { | ||
return annotations.stream().anyMatch(a -> a.getClassNode().getName().equals(groovy.transform.Trait.class.getName())); | ||
} | ||
return false; | ||
} | ||
|
||
@Override | ||
protected Element toAstElement(AnnotatedNode nativeType, Class<?> elementType) { | ||
final GroovyElementFactory elementFactory = visitorContext.getElementFactory(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,6 @@ package io.micronaut.aop.introduction | |
|
||
import io.micronaut.ast.transform.test.AbstractBeanDefinitionSpec | ||
import io.micronaut.context.ApplicationContext | ||
import io.micronaut.context.DefaultBeanContext | ||
import io.micronaut.context.event.ApplicationEventListener | ||
import io.micronaut.inject.BeanDefinition | ||
import io.micronaut.inject.InstantiatableBeanDefinition | ||
|
@@ -193,7 +192,7 @@ interface SpecificInterface { | |
then: | ||
//I ended up going this route because actually calling the methods here would be relying on | ||
//having the target interface in the bytecode of the test | ||
instance.$proxyMethods.length == 1 | ||
instance.$proxyMethods.length == 2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Groovy test is now the same as the one for Java |
||
|
||
cleanup: | ||
context.close() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -815,7 +815,7 @@ interface MyBean extends GenericInterface, SpecificInterface { | |
when: | ||
def allMethods = classElement.getEnclosedElements(ElementQuery.ALL_METHODS) | ||
then: | ||
allMethods.size() == 1 | ||
allMethods.size() == 2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Groovy test is now the same as the one for Java |
||
when: | ||
def declaredMethods = classElement.getEnclosedElements(ElementQuery.ALL_METHODS.onlyDeclared()) | ||
then: | ||
|
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.
this could also check the hashcode field for short-circuiting.
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.
I don't think it will be used without a previous hash code check.
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.
yea probably not