[hibernate-dev] Question..
Gail Badner
gbadner at redhat.com
Fri Oct 20 15:56:29 EDT 2017
Won't there be many breaking changes moving to 6.0 anyhow? I can see
keeping the signatures the same in 5.x, but I, personally, am not as
concerned about keeping them the same moving to 6.0. I would certainly
try to make the migration as painless as possible.
I'm on the fence about whether empty-creation configuration should
apply per embedded vs embeddable.
I'm going to create a gist to summarize what we've discussed, and we
can discuss further there.
On Tue, Oct 17, 2017 at 8:04 AM, Steve Ebersole <steve at hibernate.org> wrote:
> My one concern with doing this in 5.x is that we'd almost certainly change
> the signature of EmptyCompositeStrategy as we transition to 6. 6.0 has a
> real encapsulation of the embeddable in addition to the embedded. 5.x only
> really keeps the embedded (CompositeType).
>
> Anotger aspect that we have not decided is whether this empty-creation
> applies to the embeddable or the embedded. The checks would all be
> embeddable specific - the state initialization is part of the embeddable
> (the Class) so it would not change between embedded usages. We would have to
> decide if it makes sense to allow different empty-creation decisions for
> each embedded usage of that embeddable.
>
>
> On Tue, Oct 17, 2017, 9:42 AM Steve Ebersole <steve at hibernate.org> wrote:
>>
>> On Tue, Oct 17, 2017 at 12:55 AM Gail Badner <gbadner at redhat.com> wrote:
>>>
>>> >
>>> > WRT to the condition check, you suggest to "compare a primitive value
>>> > in a
>>> > composite with the default for the primitive type (e.g, comparing an
>>> > int
>>> > value with 0 instead of null)". That's not the best condition check.
>>> > I was
>>> > pointing out that we already have better handling for this for ids and
>>> > versions and that we ought to follow that paradigm, mainly on startup
>>> > we
>>> > would instantiate an instance of said component and check the initial
>>> > values
>>> > for its attributes. E.g., consider:
>>> >
>>> > @Embeddable
>>> > public class MyEmbeddable {
>>> > private int someInt;
>>> > private int anotherInt = -1;
>>> > }
>>> >
>>> > Here, comparison of `#anotherInt` to 0 is not really correct. The
>>> > proper
>>> > comparison is to -1. Again, this is exactly what we do for ids and
>>> > versions.
>>> >
>>> > So because your (A) and (B) check the same condition I was pointing out
>>> > that
>>> > they actually are based on the incorrect condition check (0 versus -1),
>>> > so
>>> > we should correct that assumption. But even then we have and further
>>> > that
>>> > we should update the check and that we still have the different outcome
>>> > between (A) and (B) to decide between.
>>>
>>> I have already implemented something that does the check that you
>>> suggested, and I decided against it for a couple of reasons:
>>> 1) Any initialized values can be "real" values.
>>> 2) Suppose an instantiated embedded value includes something like:
>>> Date created = new Date();
>>> double random = Math.random();
>>> For 2), an embedded value would never be considered empty, and its
>>> values would always be persisted instead of null.
>>
>>
>> I'm sorry but I completely disagree here.
>>
>> The Date one is interesting but ultimately can be handled somewhat easily.
>> I'll discuss why/how below.
>>
>> And the "random" is completely a fabricated case I'm guessing. Can you
>> show me a user reporting that as a real use case? Regardless I think you'll
>> agree that this is very less-than-common use-case. And anyway, it too can
>> be mitigated by the same handling I hinted at with Date. Consider:
>>
>> @Embeddable
>> class MyEmbeddable {
>> Date created = new Date();
>> double random = Math.random();
>> }
>>
>> ...
>>
>> final MyEmbeddable e1 = new MyEmbeddable();
>> final MyEmbeddable e2 = new MyEmbeddable();
>> if ( theCompositeType.isEqual( e1, e2 ) ) {
>> // we can recognize and leverage initial values
>> ...
>> }
>> else {
>> // we can't (your date/random examples)
>> // - this branch requires that either:
>> // - a strategy is supplied, or
>> // - creation of empty is disabled
>> ...
>> }
>>
>> These kind of decisions are all about covering common cases and then
>> allowing config or SPI to cover the less-common ones. It boils down to what
>> you think is more common:
>>
>> double someNumber = -1;
>>
>> or:
>>
>> double someNumber = Math.random();
>>
>> Clearly initializing to a set (magic) number is far more common.
>>
>> Also, I think you have to ask yourself about the likelihood that such a
>> component with its values initialized as such will ever be empty. At least
>> for those specific values, I think it is HIGHLY unlikely.
>>
>>
>>>
>>> I think that it should be up to the `EmptyCompositeStrategy` to decide
>>> if a primitive that has the default value, or something like `created`
>>> or `random` should be ignored when determining if an embedded value is
>>> empty.
>>
>>
>> While I do not disagree that EmptyCompositeStrategy is the most flexible
>> solution (which is why I included it as part of my "ideal" solution), the
>> majority of users do not want flexibility when that flexibility requires
>> writing some code to achieve it. They want something that JustWorks. Most
>> will be ok with configuration settings as well. For the most part, it is
>> the "power users" who are going to implement such an SPI.
>>
>> So while EmptyCompositeStrategy is certainly a good idea as part of a
>> complete solution, it is just that - a part.
>>
>>
>>> I like what you describe above.
>>>
>>> Currently the property is named
>>> `hibernate.create_empty_composites.enabled`.
>>>
>>> Are you suggesting we rename the property in 6.0+?
>>
>>
>>> For 5.x, I guess we'd have something like this to opt out:
>>>
>>> hibernate.create_empty_composites.enabled=strategy
>>> hibernate.create_empty_composites.enabled.com.acme.Person.name=false
>>>
>>> Should we also allow to disable in general, then opt-in for Person.name,
>>> as in:
>>>
>>> hibernate.create_empty_composites.enabled=false
>>> hibernate.create_empty_composites.enabled.com.acme.Person.name=true
>>> (this would fail like case (A) if the newly instantiated value has
>>> initialized values)
>>>
>>> Also, allow a strategy to be used for the opted-in value:
>>>
>>> hibernate.create_empty_composites.enabled=false
>>> hibernate.create_empty_composites.enabled.com.acme.Person.name=strategy
>>
>>
>>
>> I would do what I described in the earlier email for 5.x. This is a case
>> where the "long term solution" causes no API/SPI conflicts, and so is
>> perfectly fine for the short term as well. And not only that, but the only
>> SPI change here is what you already propose - adding a new SPI extension
>> contract (EmptyCompositeStrategy). In other words, you are already
>> proposing the only thing that would normally be a blocker to doing something
>> in a maintenance branch - adding new settings is cake compared to that.
>>
>> The new settings have different names so there is no collision. We'll
>> consider `hibernate.create_empty_composites.enabled` deprecated. We will
>> use it when no `hibernate.create_empty_composites.enabled` has been
>> specified to determine the value for `hibernate.empty_composite_creation`
>> (just like we do for other deprecated settings). For existing apps, the old
>> setting (`hibernate.create_empty_composites.enabled`) would continue to have
>> the same effect; these apps would not have the new settings, so
>> `hibernate.create_empty_composites.enabled` would define the default for
>> `hibernate.empty_composite_creation`.
>>
>> BTW, I am thinking we may do a 5.3 specifically for the new JPA MR. So we
>> could decide to do this work there rather than 5.2 - but honestly, adding
>> new settings is perfectly fine for 5.2 as already discussed.
>>
>>
More information about the hibernate-dev
mailing list