[hibernate-dev] Some thoughts on possible Binder changes
The Background Binder deals with dependencies between things. An Entity cannot be fully bound until its attributes and identifier are fully bound. An Embeddable cannot be fully bound until its sub-attributes are fully bound. One Entity might depend on another by nature of a "key many to one" or a "one to one" or a "mappedBy" or... In short, there is a lot of dependency to the order things must be bound. Some of these dependencies are *a priori* in nature. Basic attributes should be bound before embedded and associations. Attributes for a Entity/Embeddable need to be fully bound before the Entity/Embeddable can be considered complete. The Binder tries to handle these *a priori *dependencies simply by the order in which it processes things internally. This works reasonably well. The other dependencies are *a posteriori *in nature, in that we cannot fully understand them in terms of ordering until we get into the processing of the data. This includes "key many to one" or a "one to one" or a "mappedBy" examples from above. Turns out that binding of Entity and Embeddable are both functionally *a posteriori* as well because of the fact that we first create those bindings (as a shell if you will) and add the bindings for their attributes, etc after the fact. So we can't understand that either are fully resolved until after the fact. Not a huge deal, just pointing it out. The Use Case I have been working on completing identifier handling, especially in the case of composite ids. As more "background" to where my thoughts came from, let me walk y'all through how Binder currently deals with this stuff. As I mentioned above, as part of its *a posteriori* handling, Binder attempts to cycle through attributes based on their nature: 1. Process composites 2. Process simple/basic attributes 3. Process many-to-one 4. Process one-to-one 5. Process many-to-one (mappedBy) 6. Process one-to-one (mappedBy) 7. Process plural attributes 8. Process plural attributes (mappedBy) In terms of dealing with composite ids, step (1) really just means creating the Embeddable "shells" (the EmbeddableBinding instance). But at this point the EmbeddableBinding is not done, we still need its attributes "resolved" or "bound". To accomplish this, as Binder walks through the rest of the steps, it continually checks whether the completion of the attribute it just bound completes the binding of the Embeddable. So as it is looping over every attribute, for each attribute it loops over every known incomplete EmbeddableBinding and checks whether that attribute "completes" the EmbeddableBinding and if so finalizes it's binding. First thing I noticed is that that is a lot of looping (within looping). While I am sure that has some performance impact, that is not really my concern. My concern was more the non-definitive state of things being resolved. Coming back to the EmbeddableBinding as a composite id... quite a few of those steps rely on the id of an entity being fully resolved. Events Which got me to thinking about using events to signal the completion of things, and the ability to listen for these events. Don't worry, I mean events here as fairly light weight concept :) Essentially the idea is to have producers and listeners and to have Binder act as the bus. So let me apply this to the composite id case above as an example. So we'd still have an initial step that creates the EmbeddableBinding instances. It would use a EmbeddableBindingCreator delegate (I was already in the process of breaking up the 4K line Binder class to use some delegation) to do the EmbeddableBinding creation. EmbeddableBindingCreator would also implement the "listener" contract for AttributeBinding completion; as attributes are completed, if they are part of an EmbeddableBinding we "check them off" and when an EmbeddableBinding has no more unresolved sub-attributes we would finalize the EmbeddableBinding. Here, EmbeddableBindingCreator would also play a "producer" role; when the EmbeddableBinding is finalized, it would notify the bus of that. And then registered listeners for that event could react. Consider a nested composite (Embedded w/in an Embeddable): @Entity class Person { ... @Embedded Address address; } @Embeddable class Address { ... @Embedded Zip zip; } @Embeddable class Zip { .. String code; String plus4; } The initial step has EmbeddableBindingCreator create the EmbeddableBinding(Person#address) and the EmbeddableBinding(Person#address#zip). Additionally, EmbeddableBindingCreator registers the sub-attribute roles making up each EmbeddableBinding and keeps track of them (the "unresolved ones"). The second step processes basic attributes (note to self, ideally we should make sure the nested simple attributes are ordered first here): 1) Say first we'd process Person#address#zip#code; we finalize it and fire off the "attribute bound" event which EmbeddableBindingCreator gets notified o
Re: [hibernate-dev] Some thoughts on possible Binder changes
On 12 Jan 2014, at 18:56, Steve Ebersole wrote: > The Background … Thanks Steve, for this really nice summary. It is always good to share some basic design/implementation details. > In terms of dealing with composite ids, step (1) really just means creating > the Embeddable "shells" (the EmbeddableBinding instance). But at this > point the EmbeddableBinding is not done, we still need its attributes > "resolved" or "bound". To accomplish this, as Binder walks through the > rest of the steps, it continually checks whether the completion of the > attribute it just bound completes the binding of the Embeddable. So as it > is looping over every attribute, for each attribute it loops over every > known incomplete EmbeddableBinding and checks whether that attribute > "completes" the EmbeddableBinding and if so finalizes it's binding. What do you mean by “completes”. How do you know that the EmbeddableBinding is complete. > Which got me to thinking about using events to signal the completion of > things, and the ability to listen for these events. Don't worry, I mean > events here as fairly light weight concept :) For what it’s worth, Strong had once the same idea. Instead of rechecking and looping he also wanted to introduce some sort of event based processing. I thought the idea sounded promising. I am not sure how far he got or whether he even started. I think this was not long before metamodel was put on ice fore a while. > Essentially the idea is to have producers and listeners and to have Binder > act as the bus. So let me apply this to the composite id case above as an > example. So we'd still have an initial step that creates the > EmbeddableBinding instances. It would use a EmbeddableBindingCreator > delegate (I was already in the process of breaking up the 4K line Binder > class to use some delegation) +1 to anything which can break up the Binder. > Consider a nested composite (Embedded w/in an Embeddable): > > @Entity > class Person { > ... > @Embedded Address address; > } > > @Embeddable > class Address { > ... > @Embedded Zip zip; > } > > @Embeddable > class Zip { > .. > String code; > String plus4; > } > > The initial step has EmbeddableBindingCreator create the > EmbeddableBinding(Person#address) > and the EmbeddableBinding(Person#address#zip). Additionally, > EmbeddableBindingCreator registers the sub-attribute roles making up each > EmbeddableBinding and keeps track of them (the "unresolved ones"). > > The second step processes basic attributes (note to self, ideally we should > make sure the nested simple attributes are ordered first here): > 1) Say first we'd process Person#address#zip#code; we finalize it and fire > off the "attribute bound" event which EmbeddableBindingCreator gets > notified of. EmbeddableBindingCreator removes the Person#address#zip#code > attribute role from the unresolved attributes for > EmbeddableBinding(Person#address#zip). However, we see there is still more > unresolved sub-attributes, so nothing more to do. > 2) Then we process Person#address#zip#plus4, finalize it and fire off the > "attribute bound" event which EmbeddableBindingCreator gets notified of. > EmbeddableBindingCreator removes the Person#address#zip#plus4 attribute > role from the unresolved attributes for > EmbeddableBinding(Person#address#zip). Now it sees that all of the > sub-attributes for EmbeddableBinding(Person#address#zip) are resolved, and > so finalizes EmbeddableBinding(Person#address#zip), firing off its own > event that the embeddable was finalized. > > That event routes back to Binder, which directs it back to a listener for > the Person#address attribute (which was registered as waiting on the > EmbeddableBinding(Person#address#zip) as one of its attribute types). We > finalize that attribute, and fire its completion event which again > EmbeddableBindingCreator gets notified of... And so on Sounds reasonable. As always the devil is probably in the detail. I don’t know enough about the corner cases and complications to point out where this approach would cause problems. > First, there is the general pros/cons of sequential processing versus > event-driven processing. Some folks view event-driven processing as more > convoluted, harder to follow. It can not get much worse than following the 4k Binder as it stands now. Event based processing can sometimes be tricky. Maybe it would help in this case to document the approach and algorithm and the main actors. Either in the javadocs or maybe even better in an topical guide (more dev centric in this case). > Anyway... thoughts? comments? For me it is also a question of time and resources. I agree that cleaning up the binding code would be awesome, but on the other hand I thought most of the details for binding the new metamodel had been sorted out by now. Is it worth rewriting now. On the other hand, if there are real issues with the code it might be worth the try. —Hardy __
Re: [hibernate-dev] Some thoughts on possible Binder changes
Thanks for the response. See inline... On Sat, Apr 12, 2014 at 1:15 PM, Hardy Ferentschik wrote: > > On 12 Jan 2014, at 18:56, Steve Ebersole wrote: > > > The Background > > ... > > Thanks Steve, for this really nice summary. It is always good to share > some basic design/implementation > details. > > > In terms of dealing with composite ids, step (1) really just means > creating > > the Embeddable "shells" (the EmbeddableBinding instance). But at this > > point the EmbeddableBinding is not done, we still need its attributes > > "resolved" or "bound". To accomplish this, as Binder walks through the > > rest of the steps, it continually checks whether the completion of the > > attribute it just bound completes the binding of the Embeddable. So as > it > > is looping over every attribute, for each attribute it loops over every > > known incomplete EmbeddableBinding and checks whether that attribute > > "completes" the EmbeddableBinding and if so finalizes it's binding. > > What do you mean by "completes". How do you know that the > EmbeddableBinding is complete. > For embeddables, this boils down to its sub-attributes being fully bound. Ultimately we need to be able to generate the Hibernate Type. So looking at my example below, ultimately what we care about in regards to Person#address is the resolved Type for that attribute. So here, "completes" is the verb form; the idea being simply.. was the attribute we just finished processing the last unresolved sub-attribute for a embeddable; did it "complete" the embeddable in terms of all its sub-attributes now being done. As for how we know that, that depends. In the existing Binder code we literally iterate the attributes making up the embeddable and see if the Type for all those sub-attributes has been resolved. See org.hibernate.metamodel.internal.binder.Binder#completeCompositeAttributeBindingIfPossible for the current process. I am suggesting this change to use events as outlined below. > > > Which got me to thinking about using events to signal the completion of > > things, and the ability to listen for these events. Don't worry, I mean > > events here as fairly light weight concept :) > > For what it's worth, Strong had once the same idea. Instead of rechecking > and looping he also wanted to > introduce some sort of event based processing. I thought the idea sounded > promising. > I am not sure how far he got or whether he even started. I think this was > not long before metamodel was put on > ice fore a while. > To be honest, I had the same suggestion for HBMBinder as well even back in the day to get out of second passes. I think its a somewhat natural paradigm for the type of problem domain here. > > > First, there is the general pros/cons of sequential processing versus > > event-driven processing. Some folks view event-driven processing as more > > convoluted, harder to follow. > > It can not get much worse than following the 4k Binder as it stands now. > Event based processing > can sometimes be tricky. Maybe it would help in this case to document the > approach and > algorithm and the main actors. Either in the javadocs or maybe even better > in an topical guide (more > dev centric in this case). > True with the "it can't get much worse" aspect. I think sequential processing is fine/great if the thing you are doing is relatively simple. I think its safe to say that this is not simple :) > > > Anyway... thoughts? comments? > > For me it is also a question of time and resources. I agree that cleaning > up the binding code would be > awesome, but on the other hand I thought most of the details for binding > the new metamodel had been > sorted out by now. Is it worth rewriting now. On the other hand, if there > are real issues with the code > it might be worth the try. > I think "cleaning up" and "paradigm shift" are different beasts. Yes cleaning up can be done any time (even later) relatively easily. Completely shifting the underlying principles by which you attack a problem is altogether different in my mind; I think the approach is best ironed out from the onset. That being said, a lot of the actual functionality is already in place. Its just a matter of organizing it slightly differently in most cases. As for most cases being handled... well the 492 *uses* (not tests mind you, uses equate to one or more tests) of FailureExpectedWithNewMetamodel would beg to differ. And that's not counting envers in any way which currently has tons of failures because of the shift to metamodel. Lots of things simply do not work yet in metamodel. ___ hibernate-dev mailing list hibernate-dev@lists.jboss.org https://lists.jboss.org/mailman/listinfo/hibernate-dev