Skip to content
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

Optimize annotation metadata resolution performance #1717

Merged
merged 2 commits into from
May 25, 2019

Conversation

graemerocher
Copy link
Contributor

@graemerocher graemerocher commented May 24, 2019

Turns out annotationMetadata.getValue(SomeAnnotation.class, "foo", String.class) is expensive in its current form. I don't want to break the behaviour of that method and type conversion is sometimes useful so this adds new methods like stringValue, intValue, longValue etc. which are optimized forms that are much much faster. Generally one should favour these methods unless you really want type conversion.

@graemerocher graemerocher requested a review from jameskleeh May 24, 2019 12:39
* @param member The member
* @return THe {@link OptionalInt} value
*/
default @Nonnull OptionalInt intValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the @Nonnull annotation may be redundant here. Kotlin treats Optional as non null without the annotation. I haven't tested OptionalInt, though I assume it works the same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks will remove them

* @return The string values if it is present
*/
default @Nonnull String[] stringValues(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
return StringUtils.EMPTY_STRING_ARRAY;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this implementation default to getting the values the old way?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could do, but the old ways performance is not good. This method is overridden anyway be the implementation. I put this in there for backwards compatibility so if someone had implemented this interface (unlikely) it would still compile.

.build()

expect:
av.intValue().asInt == 10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this behavior is somewhat surprising. I can imagine someone using this and only receiving the first value and assuming that was all that was set in the annotation. Perhaps we should throw an exception in this case

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Annotation values are bit different, it is common to use arrays to represent "no value" in annotation definitions even if you only care about the first value. eg. Class[] foo() default {} or int[] bar() default {}

This is just a convenience method so that libraries can specify if they only care about a single int value or many. What is probably missing from the impl is all the variants for array types (like intValues() etc.)

@@ -71,8 +71,7 @@ public void process(BeanDefinition<?> beanDefinition, ExecutableMethod<?, ?> met
boolean sensitive = configuration
.isSensitive()
.orElseGet(() -> beanDefinition
.getValue(Endpoint.class, "defaultSensitive", Boolean.class)
.orElse(Endpoint.SENSITIVE));
.isTrue(Endpoint.class, "defaultSensitive"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is automatically retrieving the default value if the value isn't specified?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it isn't, but in this case the default is false hence why it made sense for this use case, and the performance is better.

@jameskleeh
Copy link
Contributor

My only concern about this going into 1.1.x is the Class -> Class<?> change. Perhaps merge it without that change and then make the change in the master branch

@graemerocher
Copy link
Contributor Author

I will revert the Class -> Class<?> change

@graemerocher graemerocher merged commit a9e5c3d into 1.1.x May 25, 2019
@jameskleeh jameskleeh deleted the performance-optimization branch August 22, 2019 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants