Open verjan-isencia opened 8 months ago
/cc @Ladicek (arc), @gsmet (hibernate-orm), @manovotn (arc), @mkouba (arc), @yrodiere (hibernate-orm)
I don't really know how Hibernate is integrated into Quarkus, but I would naively advise against using the ArC annotation overlay, because using that would tie Hibernate's lifecycle to ArC's lifecycle to certain degree (at least on the level of build step ordering). Hibernate could have its own annotation overlay, just like RESTEasy Reactive.
What I actually am looking for, is a way to decorate the JPA entities at build-time, similar to what ArC allows through their annotation overlay. Whether it's a good idea or not to reuse the same overlay is only a secondary implementation decision. I would be inclined to say it is: as I understand it, this is an early step in the build process, where the jandex metadata is manipulated before consumers of these metadata start using it.
If reusing the same overlay is not acceptable, I would suggest to allow to add a similar overlay for Hibernate, as it seems to me as a powerful way to customize the orm metadata.
IMO there are two ways to look at this:
With that in mind, I'd suggest the following ways forward:
@TemporalUnit(SECONDS)
in custom typesFor 1
, @FroMage and I have have advocated for having an overlay for Jandex in Smallrye :).
I don't think it should be the same overlay for all extensions, just the same API
But I think that should be discussed in a different issue
Yep, I was suggesting to open feature requests to the Hibernate ORM project directly, or continue the discussion on existing ones https://hibernate.atlassian.net/browse/HHH
I don't think it should be the same overlay for all extensions, just the same API
Feel free to try, but Hibernate ORM itself (not the Quarkus extension) doesn't rely on Jandex for annotation processing, so... short of bytecode transformation (which necessarily applies to every extension), I don't think you'll get anywhere.
There is work in progress to make Hibernate ORM leverage Jandex, but that'll probably only land in ORM 7.0, and I suspect full support will take even more time (due to legacy APIs/SPIs that require exposing Class
/Annotation
types).
Even if Jandex contained an implementation of the annotation overlay (I still intend to do this, but it's been low priority), the important question is: should there be a single instance shared across all Quarkus extensions, or should each extension have its own instance of the overlay? There are good arguments for both answers.
or should each extension have its own instance of the overlay? There are good arguments for both answers.
Yeah, I don't have a good answer... My feeling is that they should be different in the interest of keeping backward compatibility (which theoretically could break if extensions start meddling with a shared index)
Practically speaking, there is one annoying issue with annotation overlays - transformations ordering. Ideally, transformations should be run in deterministic order and transformation authors should be able to express that their transformations should be run before/after others (which is easier said than done). For example, AnnotationsTransformer
from ArC has the concept of priority
but that's not ideal. So if it's global/shared then we could expect more problems like that because more transformations can step on each other's feet.
That said, a global overlay would be probably more correct and efficient :shrug:.
Every ordering problem has been solved with @Priority
š If it's good enough for them, it's good enough for us ;)
And I'm strongly in favour of having a single overlay for every extension, because I've had to add overlays for Arc and Hibernate Reactive at the same time, and that's confusing as hell.
Also, for good or evil, some extensions look at annotations from other extensions, so this would avoid surprises where one extension would not see the overlaid annotation from the other extension.
And last, I've seen many bugs where parts of an extension was using the overlay API and other parts using the Jandex API, and I really think the overlay should not be a different API to Jandex's main API.
But those are all points that belong in a different issue discussing the Jandex overlay API, probably not this one :)
Every ordering problem has been solved with
@Priority
š If it's good enough for them, it's good enough for us ;)
Hehe, a good one :D
And I'm strongly in favour of having a single overlay for every extension,
Just to be clear - you're in favor of a "global" overlay shared by all extensions, right? Your wording can be IMO interpreted in different ways...
because I've had to add overlays for Arc and Hibernate Reactive at the same time, and that's confusing as hell.
Hibernate Reactive has an overlay?
Also, for good or evil, some extensions look at annotations from other extensions, so this would avoid surprises where one extension would not see the overlaid annotation from the other extension.
That's a good point.
And last, I've seen many bugs where parts of an extension was using the overlay API and other parts using the Jandex API, and I really think the overlay should not be a different API to Jandex's main API.
Sounds good but might be tricky in terms of implementation. Furthermore, there are cases where an extension needs to obtain the original metadata and not the transformed ones. Even the transformers sometimes need to access the original index. In other words, you will still need the original Jandex index around and so this kind of issue is not going to disappear. At best there will be two Jandex indexes - original and transfomed (overlay).
But those are all points that belong in a different issue discussing the Jandex overlay API, probably not this one :)
:100:
If anyone wants to discuss annotation overlay, here's a good place: https://github.com/smallrye/jandex/issues/255
But I feel compelled to address one point here:
And last, I've seen many bugs where parts of an extension was using the overlay API and other parts using the Jandex API, and I really think the overlay should not be a different API to Jandex's main API.
Sounds good but might be tricky in terms of implementation.
It's not tricky, it's impossible. Not without a massive breaking change.
I've been toying with the idea of moving the ArC implementation of CDI Language Model to Jandex (as a separate module, not to the core) and recommend gradually migrating to that. The reason is that the CDI Language Model is a set of interfaces, not classes, so you can put an annotation overlay on top of Jandex there without breaking the consumers. The downsides are obvious, of course.
Not without a massive breaking change
That's also the reason I disagree with @mkouba and @FroMage and think we should not do it
If anyone wants to discuss annotation overlay, here's a good place: https://github.com/smallrye/jandex/issues/255
:+1:
Not without a massive breaking change
That's also the reason I disagree with @mkouba and @FroMage and think we should not do it
@geoand I'm sorry but what exactly do you disagree with? I mean I didn't say we should do one or the other ;-)
If I parsed your comments above incorrectly, my bad :)
I have checked smallrye/jandex#255 and smallrye/jandex#117: the ideas of having some global overlay for annotations in Jandex, and to use Jandex for Hibernate have been hovering around for some time already.
I fit into the profile of those framework builders that have their own annotations and want to (re)decorate beans/entities during build-time. For CDI and for RestEasy, that is already possible now in Quarkus, but each using its own overlay. And my original question in this issue was if something similar would be possible for Hibernate.
As I understand so far, that would require:
It is a lot to ask, and won't be possible short-term, I know. But my suggestion is to at least think in that direction.
Just to be clear - you're in favor of a "global" overlay shared by all extensions, right? Your wording can be IMO interpreted in different ways...
Yes
Hibernate Reactive has an overlay?
Sorry, I meant RESTEasy Reactive.
Furthermore, there are cases where an extension needs to obtain the original metadata and not the transformed ones. Even the transformers sometimes need to access the original index.
Really? In which cases? I can't think of one, but I'm probably overlooking something.
Even the transformers sometimes need to access the original index.
Really? In which cases? I can't think of one, but I'm probably overlooking something.
For example, here we need to analyze the class hierarchy to find out if there is an injection point or so: https://github.com/quarkusio/quarkus/blob/main/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/AutoAddScopeProcessor.java#L77-L79. It's not 100% correct but it's a good enough approximation :shrug:.
Well this looks like the overlay doesn't have the API to look up that info, so you turn to the index. But if the index had the annotation overlay inside, you wouldn't need two APIs, no?
Unless again, I'm missing the point of why would anyone want to look for non-overlayed info.
Well this looks like the overlay doesn't have the API to look up that info, so you turn to the index. But if the index had the annotation overlay inside, you wouldn't need two APIs, no?
The problem is that you need to build/initialize the overlay first. Imagine that your transformer (or whatever we call it) transforms annotations of a class and at the same time you need to inspect a class hierarchy for annotations inside the transformer (which is what we do in the example above)... and boom, a cycle/chicken-egg problem is here.
Oh, I see. But that's an API issue. An overlay has to be able to indeed build upon the previous index in order to compose on top of it.
I thought there was a use-case for extensions to access the non-overlaid index, which is different, IMO.
I thought there was a use-case for extensions to access the non-overlaid index, which is different, IMO.
I actually used this property here: https://quarkus.io/blog/solving-problems-with-extensions-2/#annotationtransformers-to-the-rescue .
Agreed it's an ugly workaround but I would have been stuck otherwise.
we could hide the annotations from ArC using an annotations transformer while keeping them available for Airline to consume them via reflection
If this is the goal, this does not conflict with what we're saying here. Only an annotation transformer would need access to the non-overlaid index, and every index user would see the overlaid index.
Unless you're saying you need to hide the annotation from the Arc extension, but keep it visible to other extensions? Not talking about reflection and modification of bytecode here. Just how other extensions see it.
Description
Arc allows to modify/add/remove annotations at build time on a bean, with the contract that the (CDI) container will use these transformed annotations (stored in
io.quarkus.arc.processor.AnnotationStore
) to setup its metadata.This could be a powerful tool to customize also Hibernate ORM metadata: by adding annotations to entity classes in a BuildStep, one could f.i. automate definition of converters and types that are parameterized based on class metadata, or automate definition of filters.
To give a small example: I was looking for a way to define automatic conversion of
Duration
attributes, where I want to control the unit of duration stored in the database. With HibernateUserType
I can register aDurationType
that will correctly convertDuration
attributes without need for an annotation, but it does not allow me to parameterize that type except adding the unit as a parameter to the@Type
annotation:Having the option to modify annotations during build, I could do the following:
where the
@TemporalUnit
annotation (mine) is optional, and if present could be processed during buildTime to add the proper@Type
annotation with corresponding parameters.And another example: I am among the ones that cannot live with the new
@SoftDelete
implementation of Hibernate, since we need to be able to see deleted many-to-one related entities. So I have to fallback on a solution that combines@SQLDelete
with@FilterDef
and@Filter
annotations. A nice solution could be to process the existing@SoftDelete
annotation and reconvert it into the set of fore-mentioned annotations during buildTime, before Hibernate has started recollecting its metadata.So my question is: would it be possible that the Quarkus hibernate-orm extension uses the Arc
AnnotationStore
to get the decorations from the entity classes ?Implementation ideas
No response