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
RegisterForReflection#classNames does not register full hierarchy of the class #24474
Conversation
Thanks for this! Let's see what @radcortez thinks (who opened the original issue) |
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.
Can we also add a test? I recommend looking into https://github.com/quarkusio/quarkus/blob/57f6a9d9cb288cce2b558d793948b8d0e56ea806/integration-tests/opentelemetry-vertx/src/main/java/io/quarkus/it/opentelemetry/vertx/SpanData.java, which was the trigger for the original issue. Ideally, io.opentelemetry.sdk.trace.data.SpanData
should be the only class required to be registered.
core/runtime/src/main/java/io/quarkus/runtime/annotations/RegisterForReflection.java
Outdated
Show resolved
Hide resolved
core/deployment/src/main/java/io/quarkus/deployment/steps/RegisterForReflectionBuildStep.java
Outdated
Show resolved
Hide resolved
@igorregis Thank you for your time and the PR. It is very welcomed. I've left a couple of comments to discuss but nothing major and we do need a test for this. |
Thanks for pointing me this integration test @radcortez! I've tried to run it using mvn install -Dnative with no success. Do you know any further documentation reading or should I dig the code? The error that I've got is this (in io.quarkus.it.opentelemetry.vertx.HelloRouterTest): |
Strange. If there was an issue with the test, the CI would have reported it. I did try to run it locally and it works fine for me. Can you try to rebuild the entire project from the root folder to make sure you don't have any outdated dependencies? I recommend |
You were right, I did a git pull and now everything is ok. Thank you for the tip. I'm gonna work on the tests this weekend. |
Great. Thanks! |
Thank you for the reference for this integration test. It's validating quite well the implementation. But I've found that the ReflectiveHierarchStep class requires that all class into the hierarchy must be previously loaded on Jandex index, otherwise it will be skip at this line: quarkus/core/deployment/src/main/java/io/quarkus/deployment/steps/ReflectiveHierarchyStep.java Lines 221 to 223 in 57f6a9d
Even as being detected as required with all flags turned on. I'm going to implement that loading at the RegisterForReflectionBuildStep, but that will require a code set very similar to ReflectiveHierarchyStep |
@radcortez I guess I have made all needed changes now. Regarding to tests, all I did was to change it to run as the intended behavior as you wrote before:
Reading the final code, it feels like it really should be in another buildStep to say at least, because it's clear that the RegisterForReflectionBuildStep seems to have two different responsibilities new. I can, at first, separate the BuildStep logic into another class and create a dedicated new annotation, like RegisterForSerialization for evaluation here. So we can achieve something near to what @Sanne pointed out. What do you think? |
Sure go ahead. |
Hi @radcortez, I appreciate your assistance on this first time endeavor. I'm sure it's done now. The SpanData have been changed so now it uses the new Annotation and it's passing clearly. We have a new BuildStep class and a New explicit annotation that makes clear the serialization intent. I didn't feel the need for a new BuildItem. The ReflectiveHierarchyBuildItem did the trick and it keeps the semantics since we are dealing with a kind of Reflective Hierarchy If you think it's OK to go ahead, I need some help on cleaning my commits, that seems to be messy :-) Just point me the direction.
That's my case, I don't have a clue of how to do that. |
Thanks. Lets see if the CI is happy. |
This comment has been minimized.
This comment has been minimized.
It seems it didn't like it :-p. I'm going to work on it next free time that I have. |
Thanks! |
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.
Added a few comments. As Roberto mentioned, this will need a big squash at the end.
core/deployment/src/main/java/io/quarkus/deployment/steps/RegisterForReflectionBuildStep.java
Outdated
Show resolved
Hide resolved
.../deployment/src/main/java/io/quarkus/deployment/steps/RegisterForSerializationBuildStep.java
Outdated
Show resolved
Hide resolved
.../deployment/src/main/java/io/quarkus/deployment/steps/RegisterForSerializationBuildStep.java
Outdated
Show resolved
Hide resolved
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.
@igorregis welcome to Quarkus and thank you for opening this PR :)
The way I understand it, the intention of this PR was to give Quarkus applications the ability to register the whole class hierarchy of a class (or a set of classes) with a single annotation.
IMO this should be implemented through an optional parameter being passed to RegisterForReflection
, e.g. a boolean called includeHierarchy
and not in a separate annotation. But even if a separate annotation is dimmed necessary it shouldn't be called RegisterForSerialization
as such an annotation is expected to do something else.
Interestingly though, RegisterForSerialization
is an annotation we have been wanting to implement for some time now (see #20300), so I would suggest keeping it as well (addressing the issues I mention in my review).
So to sum up, I believe that this PR should:
- Extend
RegisterForReflection
to allow it to register the whole hierarchy - Deprecate
RegisterForReflection
'sserialization
parameter - Introduce
RegisterForSerialization
(as it's already there) which should register the class and its hierarchy for reflection including all fields (ideally excluding transient ones) and ideally excluding all methods, except forwriteObject
,readObject
andreadObjectNoData
, as they are not needed for serialization.
core/runtime/src/main/java/io/quarkus/runtime/annotations/RegisterForSerialization.java
Outdated
Show resolved
Hide resolved
core/runtime/src/main/java/io/quarkus/runtime/annotations/RegisterForSerialization.java
Outdated
Show resolved
Hide resolved
...tion-tests/opentelemetry-vertx/src/main/java/io/quarkus/it/opentelemetry/vertx/SpanData.java
Outdated
Show resolved
Hide resolved
Actually here I was quoting the quarkus documentation :-) since I surely need some orientation on how to perform the squash. Any link to any documentation or tutorial is suffice. |
...tion-tests/opentelemetry-vertx/src/main/java/io/quarkus/it/opentelemetry/vertx/SpanData.java
Outdated
Show resolved
Hide resolved
private void addMethodsForSerialization(BuildProducer<ReflectiveHierarchyBuildItem> reflectiveClassHierarchy, | ||
ClassLoader classLoader, Set<DotName> processedReflectiveHierarchies, IndexView indexView, DotName initialName, | ||
ReflectiveHierarchyBuildItem.Builder builder, ClassInfo classInfo, boolean methods) { | ||
List<MethodInfo> methodList = classInfo.methods(); | ||
for (MethodInfo methodInfo : methodList) { | ||
// we will only consider potential getters | ||
if (methodInfo.parameters().size() > 0 || | ||
Modifier.isStatic(methodInfo.flags()) || | ||
methodInfo.returnType().kind() == Kind.VOID || methodInfo.returnType().kind() == Kind.PRIMITIVE) { | ||
continue; | ||
} | ||
registerType(reflectiveClassHierarchy, classLoader, processedReflectiveHierarchies, | ||
methods, builder, | ||
getMethodReturnType(indexView, initialName, classInfo, methodInfo)); | ||
} | ||
} |
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.
Non-blocker: I still don't see why serialization/deserialization would use the getters instead of reflection to access the fields. If you could provide an example where getters are accessed/used I would appreciate it :)
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.
Sure. We are not using the getters per se, but only to guess what field should we register the type from. That way we are registering types returned by public methods, since I'm guessing that its state is needed to be transferred or stored.
If I stop doing that, the opentelemetry vertex integration test break due to lack of type when you run it on native.
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.
Why not register the types of all the fields though? Wouldn't that be safer?
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.
That crossed my mind, but I've noticed that many types returned on opentelemetry vertex integration test are just interfaces, so they have no fields to be registered and we have no access (the developer may not know and not asking them to be registered) to the real objects behind those interfaces.
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.
Thanks for the changes @igorregis . Please see a couple of comments, only the one with the try catch is a blocker for me.
core/deployment/src/main/java/io/quarkus/deployment/steps/RegisterForReflectionBuildStep.java
Outdated
Show resolved
Hide resolved
core/deployment/src/main/java/io/quarkus/deployment/steps/RegisterForReflectionBuildStep.java
Outdated
Show resolved
Hide resolved
core/deployment/src/main/java/io/quarkus/deployment/steps/RegisterForReflectionBuildStep.java
Outdated
Show resolved
Hide resolved
Ok, I m on a vacation trip. So I'm going to be able to do this changes in 2 weeks. |
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.
LGTM, thanks for addressing all the blocking issues @igorregis
My fork was too behind so I discarded all changes on my main. I had no idea it would close the PR, sorry for that. I still have all history on my fork's feature branch. |
FYI: In such cases
That's OK.
Yes I think opening a new PR that will be referencing this one is OK.
That got me really confused :) |
Hi @zakkak @igorregis , I try to understand in which case we don't want the full hierarchy to be registered for reflection as soon as with register a class ? |
Hi @humcqc
I think that would make sense when you have a performance concern. To registry everything for reflection pose a weight into the build process and influence the final binary size (AFAIK), and I guess it also add some weight into the runtime. But more experienced Quarkus developers should validate what I wrote here.
I guess it's something new to be discussed into another issue, where we can explore the scenarios in witch an annotation is the anchor or trigger to a hierarchy reflection. That seems to be fair to me, but I'm sure we need to explore more this need. |
Hi @igorregis , thanks for your quick reply, For the second point: |
Hi @humcqc
We probably need to mention the defaults in the class description to make this clear. I opened #38496 Regarding the whys, what @igorregis mentions in #24474 (comment) is correct.
As suggested by @igorregis please open a new issue for this or try starting a discussion in https://quarkusio.zulipchat.com/#streams/187038/dev or https://github.com/quarkusio/quarkus/discussions |
fix #21985