Skip to content

Refine customization of EntityInformation #3288

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

Closed
JonasProgrammer opened this issue Apr 25, 2025 · 2 comments
Closed

Refine customization of EntityInformation #3288

JonasProgrammer opened this issue Apr 25, 2025 · 2 comments
Assignees
Labels
type: enhancement A general enhancement

Comments

@JonasProgrammer
Copy link

JonasProgrammer commented Apr 25, 2025

Hi,
I currently have the problem of marking an entity as new, even though it has a non-null UUID as id. The basic idea is to use a null-object pattern with the special case of a new UUID(0, 0), rather handling Nullability.

Reading around spring-projects/spring-data-relational#1587 either Persistable or providing a custom EntityInformation is suggested. For my use-case, Persistable has the downside of clashing with data class definitions in Kotlin having a id member, which clashes with the getId function (though it does not satisfy the interface somehow...).

EDIT: Forgot to mention I am using Spring Boot 3.4.4, which, as far as I can tell, matches the version of spring-data-relation, spring-data-r2dbc, and the common shared stuff.

So I tried to go down the road of supplementing a R2dbcRepositoryFactoryBean with getEntityInformation overridden to return a delegate of the super call, overriding isNew to my liking. The factory bean does get instantiated once per repository, but the getEntityInformation method never gets called (both verified using breakpoints in the debugger). Returning a delegating subclass of R2dbcRepositoryFactory with a similar approach to its getEntityInformation method yielded the same result.

So when one would want to go down the rabbit hole of providing a custom implementation for EntityInformation, how does one actually do this properly?

Kind regards

--
Aside from that, as a meta question: We have the null/0-default hardcoded logic, Persistable as an intrusive way of doing things, and (presumably) EntityInformation working very low-level. Is there a specific reason, why something in between is unfeasable? I saw a EntityIsNewStrategy with implementations for the hardcoded null/0, and the persistable logic.
One could give the user the ability to supply something akin as beans. And while I get not going through a chain as in web filters, for example, for performance reasons, one could choose the best matching implementation from an ordered list, where each participant could implement a boolean supports(Class<?> domainType) or something.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Apr 25, 2025
@mp911de mp911de self-assigned this Apr 28, 2025
@JonasProgrammer
Copy link
Author

So I have found the root cause: Subclassing R2dbcRepositoryFactory was the actual culprit.

getTargetRepository calls a private version of getEntityInformation with an additional (albeit unused) argument. Its own override of the public getEntityInformation delegates there, but there is no chance of actually overriding the behavior at this point.

My current workaround is to just override getTargetRepository instead, copying the implementation from the base-class and keeping a copy of the private fields myself from the constructor. This works so far, although I am not too happy with relying on copied code doing reflection magic, as the constructor signature may change at any notice.

So far, the actual issue is solved for me with a somewhat ugly workaround. Given the other issues regarding the new entity detection, perhaps some middle-ground between hard-coded, Persistable, or RepoBeanFactory magic would still be nice. Or at least have the default implementation play nice with customization points, so subclassing to achieve the behavior in a more reliant way is possible.

I will leave this one open for now, as I am not really sure wether the way stuff currently works is intuitive. If the discussion is better suited elswhere, just close this please.

@mp911de
Copy link
Member

mp911de commented May 13, 2025

EntityInformation is an abstraction used for repositories ultimately delegating to PersistentEntity and for the is-new case, using PersistentEntity.isNew(…). Because of this arrangement, we don't really want to allow custom implementations of EntityInformation, however, it isn't great that we have potentially two variants of EntityInformation when the protected method is overridden.

In any case, that is a general theme across all of our Spring Data modules and that issue needs to be solved at the level of Spring Data Commons.

I think you could provide a subclassed MappingContext with a specific RelationalPersistentEntity delegate variant that customizes the isNew(Object) method for the specific entity type.

@mp911de mp911de transferred this issue from spring-projects/spring-data-relational May 13, 2025
@mp911de mp911de changed the title Marking entity as new using EntityInformation fails Refine customization of EntityInformation May 13, 2025
@mp911de mp911de added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels May 13, 2025
@mp911de mp911de added this to the 4.0 M3 (2025.1.0) milestone May 13, 2025
mp911de added a commit that referenced this issue May 13, 2025
We now provide a getEntityInformation(RepositoryMetadata) customization hook for EntityInformation creation as several modules require access to RepositoryMetadata details (such as the Id type).

Closes #3288
@mp911de mp911de closed this as completed May 13, 2025
mp911de added a commit that referenced this issue May 16, 2025
We now provide a getEntityInformation(RepositoryMetadata) customization hook for EntityInformation creation as several modules require access to RepositoryMetadata details (such as the Id type).

Closes #3288
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants